Привет, меня зовут Даг. Я был разработчиком в течение нескольких лет, и теперь работаю в качестве ведущего инженера на Shamazi. За этот период я написал много разных пользовательских учреждений и узнал много способов структурировать код React.
На этой неделе я хотел поделиться своим опытом пользовательских реактивных крючков, которые я нашел наиболее полезным для производства веб-сайтов в самый простой самый простой путь.
Реагировать крюки
Сначала были введены крючки для реагирования в версии 16.8, после дразницы в 2018 году. Есть фантастическая гида, представляющая их на Веб-сайт RACT Отказ Проще говоря, они являются способом писать побочные эффекты для функциональных пользовательских интерфейсов. Это позволяет писать части вашего пользовательского интерфейса в качестве функций JavaScript, но все еще имеют возможность управлять состоянием, вызововать API, используйте хранилище, аутентифицировать пользователей и так далее.
React предоставляет некоторые крючки из коробки ( Usestate
, Useffect
и упреждающий текст
Быть главным три). Кроме того, он позволяет составлять свои собственные крючки для более высокого уровня, чтобы отделить логику многоразового использования. Эти пользовательские крючки – это то, что я буду исследовать здесь. Вот три, которые я нашел самым полезным по ряду продуктов, которые мы производим на Shamaazi.
Выполнение асинхронных действий
Большинство сайтов должны выполнять некоторую форму асинхронных действий, будь то загрузка данных для отображения на странице или отправка данных на основе ввода и действий пользователя. Полезно отслеживать состояние этих асинхронных действий; Это в настоящее время загрузка? Это вернуло результат? Была ли ошибка?
Мы нашли много наших компонентов, которые начали совмещать много подобного кода, либо для получения данных о начальной нагрузке или для отправки данных. Это выглядело как следующее:
const MyComponent = () => { const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const [result, setResult] = useState(null) useEffect(() => { const loadData = async () => { setResult(null) setError(null) setLoading(true) try { const result = await doSomeAction(); setResult(result) } catch (e) { setError(e) } finally { setLoading(false) } loadData() }, []) if (loading) { return <>loading... } if (error) { return <>something broke } return <>{result} }
Вся эта нагрузка и логика ошибок могут быть вытянуты в крючок, делая наш интерфейс много Neater.
const MyTidyComponent = () => { const {loading, result, error} = useAsync(doSomeAction) if (loading) { return <>loading... } if (error) { return <>something broke } return <>{result} }
Это seasync
Крюк отвечает за управление загрузкой, ошибкой и состояниями результатов, удаляя необходимость всего этой логики внутри фактического компонента. Это также позволяет нам повторно использовать это во всем нашем приложении. Это массивно упрощает загрузку данных на страницу.
В качестве бонуса мы обнаружили, что мы также хотели выполнить возможность выполнять действие позже, а не только тогда, когда компонент создан. Это полезно для выполнения асинхронных действий, основанных на входе пользователя; Действия, такие как отправка формы, могут использовать один и тот же крюк, но пройти ложь
значение в качестве второго параметра. Это указывает на то, что они не хотят, чтобы действие было выполнено сразу.
const { execute, loading, result, error } = useAsync(submitSomeForm, false)
Мы также обнаружили, что крюк иногда вызывал утечку памяти, если форма Porm передается от компонента (например, форма может ответить на следующую страницу, когда она отправляется, но настроек загрузка
на False
Вы были забраны вдали от формы – это утечка памяти). Мы обработали это, отслеживая, установлен ли крючок на странице (отслеживается через USEREF
). Мы обновим только любое состояние, если компонент все еще присутствует. Это позволяет избежать любых утечек памяти.
Полная версия нашего seasync
Крюк здесь:
import { useEffect, useState, useCallback, useRef } from 'react' export default (asyncFunction, immediate = true) => { const [loading, setLoading] = useState(false) const [result, setResult] = useState(null) const [error, setError] = useState(null) // Track a reference to whether the useAsync is actually on a mounted component. // useEffect below returns a cleanup that sets this to false. Before setting // any state, we check if the cleanup has run. If it has, don't update the state. const mounted = useRef(true) useEffect(() => { return () => { mounted.current = false } }, []) const execute = useCallback(async (...args) => { setLoading(true) setResult(null) setError(null) try { const r = await asyncFunction(...args) if (mounted.current) { setResult(r) } return r } catch (e) { if (mounted.current) { setError(e) } } finally { if (mounted.current) { setLoading(false) } } }, [asyncFunction]) useEffect(() => { if (immediate) { execute() } }, [execute, immediate]) return { execute, loading, result, error } }
Обновление LocalStorage или SessionStorage
В рамках некоторых из наших продуктов мы заполним «корзина для покупок». Это держит трассу того, что делает пользователь. Иногда мы хотим, чтобы это сохранилось, даже если они перемещаются от нашего сайта, обновляют страницу или закрывают браузер. Для этого мы используем комбинацию LocalStorage и SessionStorage.
Реагирование сама не обеспечивает никаких крючков для хранения данных в LocalStorage
или SessionStorage
, но мы хотели последовательный опыт с Уместите
Отказ Реально, это не должно быть сложнее использовать LocalStorage
Чем бы это было бы использовать штат нормально.
Например, мы могли бы использовать LocalStorage
отслеживать вход пользователя.
const storageComponent = () => { const [value, setValue] = useLocalStorage('storage_key', 'default_value') return setValue(e.target.value}/> }
Наши крючки для достижения этого выглядят следующие:
const useStorage = (key, initialValue, storage) => { // Pass initial state function to useState so logic is only executed once const [storedValue, setStoredValue] = useState(() => { try { const item = storage.getItem(key) return item ? JSON.parse(item) : initialValue } catch (error) { console.error(error) return initialValue } }) useEffect(() => { try { // Update storage every time the value is changed storage.setItem(key, JSON.stringify(storedValue)) } catch (e) { console.error(e) } }, [storedValue, storage, key]) return [storedValue, setStoredValue] } export const useLocalStorage = (key, initialValue) => { return useStorage(key, initialValue, window.localStorage) } export const useSessionStorage = (key, initialValue) => { return useStorage(key, initialValue, window.sessionStorage) }
Аутентификация пользователей
Супер общий сценарий, который мы столкнулись с кучей компонентов, которые все оставляют, вошел ли пользователь войти в систему. Они часто заботятся о том, чтобы действовать на пользователю, через методы, такие как Вход
, выйти
или ResetPassword
Отказ
Чтобы сохранить все эти компоненты в синхронизации, мы хотим только один источник информации о текущем пользователе. Мы могли бы сделать это, имея компонент, упаковочную нашу нашу приложение, которое управляет Пользователь
состояние, и проходит какие-либо опоры, где они используются для Пользователь
, Вход
, выйти
или ResetPassword
методы.
Это быстро становится грязным, хотя, с множеством компонентов, которые на самом деле не заботятся о том, чтобы пройти Пользователь
авторизоваться
и Выход
Реквизирует, даже если они не используют их сами – только ребенок их делает.
К счастью, реагирует, обеспечивает идею контекст Отказ Позволяя нам решить эту проблему.
Мы можем создать контекст аутентирования и использовать крючок, чтобы получить любую информацию, которую мы хотим. Мы также можем встроить наши призывы ATH API в этот контекст.
Это будет похоже на следующее, чтобы использовать:
// In our top level App.js import { ProvideAuth } from 'hooks/useAuth' export default () => { return} ...
// in a component that wants to use Auth import useAuth from 'hooks/useAuth' export default () => { const { user, login, logout, resetPassword } = useAuth(); return <> {user} }
Сам этот крючок выглядит следующим образом:
import React, { useCallback, useState, useEffect, useContext, createContext } from 'react' const authContext = createContext() // Hook for child components to get the auth object and re-render when it changes. export default () => { return useContext(authContext) } // Provider component that wraps components and makes useAuth() available export function ProvideAuth({ children }) { const auth = useAuthProvider() return{children} } // Provide Auth hook that creates auth object and handles state function useAuthProvider() { const [user, setUser] = useState(null) // Get the logged in user when created useEffect(() => { const user = getLoggedInUser() setUser(user) }, []) const login = async (...) => { const user = ... setUser(user) } const logout = async () => { ... setUser(null) } const resetPassword = async () => { ... } return { resetPassword login, logout, user } }
Это имеет дополнительное преимущество сохранения всей логики аутентификации. Чтобы изменить другому провайдеру авторизации, нам нужно было бы только изменить этот файл.
Заключение
React предоставляет некоторые действительно мощные абстракции для создания кода, который аккуратно организован и легко читает. Здесь мы посмотрели на три реактивных крючка, которые я нашел самым полезным: seasync
Для выполнения асинхронных действий либо при создании компонента или когда пользователь выполняет действие, УПЕСТРАЖАЕТЬ
Для использования LocalStorage
и SessionStorage
так же, как Уместите
и, наконец, Useauth
Для управления пользователями и аутентификацией.
Эти три крючка предоставляют мощные абстракции, которые позволяют вам построить реагировать компоненты простым способом.
Есть ли у вас другие пользовательские реактивные крючки, которые вы найдете полезными? Думаю, я пропустил какие-либо ключевые? Пожалуйста, дайте мне знать.
Ищете другие способы сохранить ваш код организован? Проверьте мою статью о написании неизменного кода.
Наслаждался этим постом? Хотите поделиться своими мыслями по этому вопросу? Нашел эту статью полезной? Не согласен со мной? Дайте мне знать по Объедините меня в Twitter Отказ
Оригинал: “https://dev.to/dglsparsons/3-amazing-react-hooks-to-keep-your-code-organized-neatly-ghe”