
Всем привет!
Все мы прекрасно знаем что построить полноценный стор на react context достаточно тяжело, а оптимизировать его ещё тяжелее.
А что если я расскажу как это можно сделать быстро и просто?
Введение
Буквально каждую конференцию мы слышим от спикеров, а вы знаете как работают контексты? а вы знаете что каждый ваш слушатель перерисовывает ваш умный компонент? (useContext) Пора решить эту проблему раз и на всегда!
Во-первых, обозначим проблемы:
-
Неявный DI (неясно какие сторы есть на странице и какой из десятков хуков имеет зависимость на стор)
-
Рандомные рендеры дерева, независимо от того, слушаем мы эти пропсы или нет.
-
Контексты, на самом деле, это лишь способ доставки пропсов, но мы же хотим построить полноценный стор?
1. withContext
Решая проблему неявного DI мы с моей командой пришли к выводу что нам требутся HOC который будет отрисовывать наши контексты/сторы последовательно. реализовывая всю нашу логику внутри стора и предоставляя доступ внутри компонента.
// Пример HOC export const withContexts = function <T>( Component: React.ComponentType<T>, contexts: React.ComponentType[] ) {} // Использование будет выглядеть так export default withContexts(TodoPage, [GlobalStore.Provider])
2. connectContext
Решая проблему рандомных рендеров мы рассмотрели несколько вариантов.
Кастомный хук useStore который бы отслеживал изменения контекста глобально и событиями бы сообщал о том что значение изменилось и ререндерил бы компонент в нужный момент времени. НО мы бы так и остались с проблемой не явного DI в месте использования, что доставляло бы нам немало проблем.
По этому выбор пал на HOC который бы умел принимать в себя контексты и получать только ТЕ аргументы, что мы используем.
// Пример HOC export const connectContext = function <ContextValue, ComponentProps>( Context: Context<ContextValue>, getValueByKey: (value: ContextValue) => ComponentProps ) {} // Пример использования export const StoreExample = connectContext( // Стор который используем // Стоит улучшить и сделать здесь больше чем 1 контекст GlobalStore.Context, // Значения сторов ({ state: { notifications }, actions: { updateNotifications } }) => // Значения которые получит компонент ({ globalNotifications: notifications, updateGlobalNotifications: updateNotifications, }) // Пропсы которые ожидает увидеть компонент помимо тех что получит из контекста )<{ minDate: string }>( ({ globalNotifications, updateGlobalNotifications, minDate }) => {}
3. createStore
Последняя проблему которую мы решали, была связана с тем что создание контекста всегда бойлерплейт, нам требуется создать контекст потом описать провайдер внутри которого была бы наша логика и после чего мы бы спустили наше состояние и методы обновления его вниз до слушателя.
// Пример функции которая бы создавал стор export const createStore = function <State, Actions>( // тут стоит явно расширить и научить стор слушать другие сторы, // планируем внедрить в ближайшее время useCustomHook: () => { state: State; actions?: Actions } ) {} // Пример Создания стора export const GlobalStore = createStore(() => { const [notifications, updateNotifications] = useState<string[]>([]); const [user] = useState({ name: "Grigoriy" }); return { state: { notifications, user }, actions: { updateNotifications } }; });
И так в результате этих наработок я создал библиотеку и решили поделиться ею с комьюнити.
https://www.npmjs.com/package/context-base-api
В ближайшее время я и моя команда планируем расширять возможности проекта, вы так же можете принять участие в развитие библиотеки!
Спасибо за внимание. Надеюсь на обратную связь.
P.S
В ближайшее время мы планируем выпустить в релкиз библиотеку для работы с формами которая бы позволяла управлять формой на уровне конфигурации и при этом умела бы валидировать состояние, но ещё и менять его в зависимости от условий описанных в JSON.
Следите за обновлениями!
ссылка на оригинал статьи https://habr.com/ru/post/709692/
Добавить комментарий