Использоватьэффект Анкет Крюк всем нуждается, но никто не хочет. Согласно официальным документам React, это « вытеканный люк из чисто функционального мира React в императивный мир “. Полное руководство по использованию эффективности Автор Redux и React Core Team Дэн Абрамов 49 -минутное чтение – и это занимает не менее чем вдвое больше времени к В самом деле Постичь это.
Использование настолько сложное, насколько это возможно, в ReactJS, и очень маловероятно, что вы можете написать приложение без него. Итак, давайте попробуем применить несколько хороших принципов, чтобы сделать работу с использованием более управляемой:
Я уже писал о нескольких способах уменьшения количества эффектов в серии Usestate Bidsks:
- В Часть 1 , мы установили, что некоторые эффекты можно заменить на Usememo Или даже просто нормальные выполнения функций.
- В Часть 2 Я рассказал, почему пытаться синхронизировать разные состояния реагирования с Использовать вероятно, является анти-паттерном и что вы можете сделать вместо этого.
Извлечение данных
Извлечение данных является очень распространенным побочным эффектом, который обычно управляется с Использовать . В конце концов, большинство приложений должны извлечь данные откуда -то. Сценарий настолько распространен, что есть некоторые очень хорошие библиотеки, которые не только помогут вам сделать сложную логику более декларативной, но и даст вам кучу отличных дополнительных функций.
Я явно собираюсь порекомендовать свою любимую библиотеку с открытым исходным кодом, React-Query (Я сомневаюсь, что смогу написать еще одну статью, не упоминая об этом 😅), но SWR , Аполлон а также Rtk-Query тоже великолепны. Дело в том, что не пытайтесь повторно изобрести колесо. Некоторые проблемы были решены ранее, и их стоит абстрагировать. Количество эффективности использования, которое мне пришлось написать, было резко сокращено, так как я использую React-Query.
Функция или класс должны делать одну вещь и только одну вещь. Ваш Процедура
Надеемся, что функция будет только обработать платеж, а также не перенаправлять пользователя где -то, потому что это не его ответственность. Тот же принцип применим к функции, которую вы выполняете Использовать . Нет необходимости заправлять все в одном Использовать :
React.useEffect(() => { document.title = 'hello world' trackPageVisit() }, [])
Здесь мы хотим выполнить некоторые операции, такие как установление заголовка документа и отслеживание посещения страницы с помощью некоторых аналитических инструментов, когда компонент «крепления». Несмотря на то, что на первый взгляд это может показаться незначительным, мы делаем две очень разные вещи в этом одном эффекте, и это можно легко разделить на два эффекта. Преимущество становится более очевидным, как зависимости от изменения эффекта с течением времени.
Предположим, теперь мы хотим добавить функцию, которая синхронизирует какое -то локальное состояние с названием документа:
const [title, setTitle] = React.useState('hello world') React.useEffect(() => { document.title = title trackPageVisit() }, [title])
Вы можете заметить ошибку? Каждый раз, когда заголовок меняется, мы также отслеживаем посещение страницы, что, вероятно, не то, что мы задумали. Плевать его на два эффекта решает проблему, и я считаю, что мы должны были сделать это с самого начала:
const [title, setTitle] = React.useState('hello world') React.useEffect(() => { document.title = title }, [title]) React.useEffect(() => { trackPageVisit() }, [])
Мало того, что код теперь менее старается, его также легче рассуждать. Каждый эффект теперь вдвое меньше, поэтому вы можете посмотреть на каждого из них в изоляции, чтобы лучше понять, что он делает.
Мне действительно не нравятся компоненты, где 50% кода – это крючковые вызовы. Обычно это показывает, что мы смешиваем нашу логику с нашей наценкой. Уравновешивая их в пользовательском крючке, есть несколько преимуществ, кроме очевидного «вы можете их повторно использовать»:
Вы можете назвать их
Давая переменные и функции хорошее имя похоже на написание документации, и то же самое относится к крючкам. Если вы используете TypeScript, вы также получите выгоду от четко определенного интерфейса:
const useTitleSync = (title: string) => { React.useEffect(() => { document.title = title }, [title]) } const useTrackVisit = () => { React.useEffect(() => { trackPageVisit() }, []) }
Все наши эффекты теперь прекрасно скрыты внутри пользовательских крючков с описательными именами. Наш компонент будет иметь только две строки крючков вместо шести, что означает, что он больше сосредоточен на своей основной ответственности: создание разметки.
Вы можете инкапсулировать логику
Это, вероятно, самое большое преимущество для меня на заказ: мы можем связывать вещи, которые принадлежат вместе, и нам не нужно все разоблачать. usetitLesync Крюк не идеален: он только охватывает эффект, и каждый компонент все еще должен управлять этим заголовком вручную. Так почему бы нам не положить Все заголовок, связанный в пользовательском крючке, чтобы инкапсулировать всю логику с ним:
const useTitle = (initialTitle: string) => { const [title, setTitle] = React.useState(initialTitle) React.useEffect(() => { document.title = title }, [title]) return [title, setTitle] as const }
Мы можем даже сделать еще один шаг вперед: если мы только намереваемся показать заголовок в заголовке документа и нигде больше, мы можем сохранить значение заголовка в крючке и разоблачить только сеттер, создавая минимальный интерфейс:
const useTitle = (initialTitle: string) => { const [title, setTitle] = React.useState(initialTitle) React.useEffect(() => { document.title = title }, [title]) return setTitle }
Вы можете проверить их изолированно
Тестирование использование Крюк без необходимости проверять компонент, который использует его, имеет то преимущество, которое вам не нужно думать обо всех других вещах, которые происходят в этом компоненте, например, отслеживание страниц. Тестирование пользовательских крючков очень похоже на тестирование любой другой функции UTIL:
import { act, renderHook } from '@testing-library/react-hooks' describe('useTitle', () => { test('sets the document title', () => { const { result } = renderHook(() => useTitle('hello')) expect(document.title).toEqual('hello') act(() => result.current('world')) expect(document.title).toEqual('world') }) })
Все вышеперечисленные причины заставляют меня хотеть написать пользовательские крючки, даже если я использую их только один раз. Но если вы не можете или не хотите извлекать его в пользовательский крючок по какой -либо причине, функция передана Использовать может иметь имя, поэтому подумайте о том, чтобы назвать ваши эффекты:
const [title, setTitle] = React.useState('hello world') React.useEffect(function syncTitle() { document.title = title }, [title])
Даже не, или на самом деле, особенно не для функций. Я просто буду отдавать здесь Дэну, потому что я не могу описать это лучше, чем он уже делает в своем Полное руководство Анкет
Еще одна вещь, которую я думаю, стоит упомянуть, это: не каждый эффект требует зависимостей. Я видел эффекты с 8+ зависимостями, некоторые из которых являются объектами, которые не запоминаются, поэтому они в любом случае вызовут эффект в каждом рендере. Так зачем беспокоиться, второй аргумент Использовать в конце концов, не является обязательным. Это пригодится, если ваш эффект использует ранние возвраты или выполняет побочный эффект условно:
const useInitializePayload = () => { const payload = usePayload() React.useEffect(() => { if (payload === null) { performSomeSideEffectThatInitializesPayload(value1, value2, ...valueN) } }) }
Массив зависимостей для этого эффекта, вероятно, будет довольно большим, или мы могли бы попытаться обмануть только [полезная нагрузка]
как зависимость. Я считаю, что оба способа быть уступающими, чтобы просто всегда выполнять эффект и преобразовать, если это необходимо.
Я надеюсь, что эти советы уменьшат сложность для вас при работе с Использовать . Дайте мне знать в комментариях ниже, как вы предпочитаете организовать свои эффекты ⬇
Оригинал: “https://dev.to/tkdodo/simplifying-useeffect-5fim”