Состояние обработки в React можно сравнить с обоюдоострым мечом, вы можете использовать его с умом или правильно, но вы также можете начать создавать технический долг, если будете использовать его неправильно.

Если объем вашего компонента ограничен, не стесняйтесь использовать минимальный подход.

Минималистичный подход

Нативные хуки появились в React с версии 16.8. В этой статье мы поговорим в основном о том, как мы должны их использовать.

Я не хочу быть исчерпывающим и писать о функциональных и классовых компонентах. Я сосредоточусь только на функциональных компонентах для всех наших примеров.

Использовать состояние

В качестве примера давайте представим, что вы хотите реализовать счетчик. И вы хотите, чтобы ваш счетчик был таким же простым, как он есть. Ваш счетчик будет просто кнопкой, которая будет увеличивать счетчик при нажатии на кнопку. Для этого вам нужно сохранить информацию о счете, и вам нужен сеттер для обновления значения.

Вот и все! Ты видишь? Это минимально, потому что здесь нам просто нужно одно состояние для обработки одного поведения.

Однако наш мир не всегда так прост, как кажется. Иногда вам нужно создавать сложные компоненты и сложные потоки для создания удивительных функций.

Представьте, что вы хотите, чтобы переключатель был включен, если счетчик достигает значения, и если вы нажмете на переключатель, он установит значение счетчика на 0.

Это становится более сложным, но давайте сделаем это только с помощью useState, useEffect, и useCallback.

Прежде всего, здесь я также использовал два других хука useCallback и useEffect. Я не буду вдаваться в подробности об этих хуках, однако вот небольшое пояснение.

  • UseEffect: по умолчанию эффекты запускаются после каждого завершенного рендеринга. Таким образом, эффект всегда воссоздается, если изменяется одна из его зависимостей. В нашем примере UseEffect сработает только при изменении счетчика.
  • UseCallBack: этот хук похож на обратный вызов, функция будет запущена компонентом Switch, когда мы нажмем на него. Он установил счетчик на 0, как и ожидалось.

Вы уже видите, что наш компонент счетчика содержит слишком много логики, давайте разделим их!

Это намного лучше, мы уменьшаем логику по компонентам и это уменьшает код, конечно, вы также можете создавать отдельные файлы для каждого компонента, чтобы повысить читаемость и правильно разделить все с хорошей иерархией.

Тем не менее, мы все еще не удовлетворены. Нам нужны реквизиты для обработки поведения счетчика в пользовательском переключателе, представьте, что нам нужно углубиться в иерархию, нам потребуется предоставить счетчик и сеттер. Это не оптимально. Есть лучший способ получить доступ к состоянию, не предоставляя все в свойствах.

Оптимальный подход

Поставщик контекста

В общем, провайдер — это хороший способ поделиться состоянием, обратным вызовом или константой в иерархии компонентов. Когда вы замечаете переменную, которая передается всем свойствам, это означает, что этого можно избежать, если у вас есть провайдер.

Однако это также полезно, когда вам нужно иметь общее состояние между компонентами.

Провайдер — это архитектура, которая позволяет нам централизовать логику и данные в одной точке.

Вот архитектура

  • _.tsx (компонент поставщика)
  • константы (общие константы и значение по умолчанию)
  • Контекст (переменная, которая создает и инициирует контекст)
  • типы (файлы, содержащие типы, если вы используете машинописный текст)
  • useProvider (крючок для получения общего обратного вызова/состояния и т. д.)

Первый файл, который я объясню, — это const.ts.

Это значение по умолчанию для запуска поставщика контекста.

Здесь нет никакого секрета, только тип значения.

Теперь все стало сложнее, здесь мы создаем контекст с помощью метода createContext из React. Это реагирующий компонент, который будет содержать значение и логику!

Теперь мы хотим обернуть нашу логику и наше возвращаемое значение вокруг этого компонента.

Как видите, мы возвращаемся к компоненту Context.Provider с нашим значением по умолчанию.

Теперь, когда у нас есть наш компонент, мы можем создать специальный хук, чтобы возвращать наш контекст каждый раз, когда нам нужно состояние или обратный вызов.

Мы используем хук useContext, который вернет наш контекст.

  • Использовать контекст

Принимает объект контекста (значение, возвращенное из React.createContext) и возвращает текущее значение контекста для этого контекста. Текущее значение контекста определяется реквизитом value ближайшего <MyContext.Provider> над вызывающим компонентом в дереве. (https://reactjs.org/docs/hooks-reference.html#usecontext)

Теперь у нас есть все, мы готовы сократить наш код!

Мы создали небольшой компонент-оболочку, который инкапсулирует наш компонент счетчика, чтобы он мог вызывать наш хук Provider для получения состояния и необходимого ему обратного вызова.

Как видите, мы сократили нашу логику внутри компонента, и нам не нужно предоставлять какие-либо реквизиты нашему CustomSwitchкомпоненту.

Вот как выглядит наш компонент CustomSwitch.

Наша читабельность значительно увеличилась, кроме того, мы отделили нашу логику от нашего компонента, плюс теперь мы можем совместно использовать обратный вызов или состояние для всего нашего третьего компонента. Это основная цель провайдера. Мы не хотим возлагать ответственность на все три компонента, мы хотим поместить их в одну точку: Провайдер.

В заключение мы все можем сказать, что существует множество способов обработки логики для нашего компонента реакции, и такая архитектура является одним из многих ответов. Не забывайте, что вы должны использовать это с умом в соответствии со своими потребностями, вам не нужна архитектура полного провайдера для небольшого состояния. Как я люблю говорить:

С великим поставщиком приходят большие обязанности.

Спасибо за чтение! 🙌

Том Клотц, инженер-программист в Castor.