Этот пост был первоначально опубликован в моем личном блог .
Некоторое время назад я читал RFC из RFC React, называемых UseMutablesource ; Это была экспериментальная особенность, которая в двух словах позволяет безопасно читать, писать и даже редактировать внешний источник (за пределами дерева компонентов React). Это особенность Бэнджера, которую я действительно за это разжигал, но в то же время экспериментально. Возможно, вы знаете, что я работаю над библиотекой государственного управления с открытым исходным кодом под названием Jotai. Эта библиотека анонсировала новую функцию, режим без поставщика. Чтобы знать, что это такое, подумайте о контексте реагирования, но не нуждается в Поставщик Компонент, это не совсем, но это дает вам идею.
Почему новый?
Да, у нас есть шаблоны и библиотеки, которые позволяют нам читать и писать из внешнего источника, но, как я уже сказал, этот позволяет вам делать вещи безопасно; больше нет разрывов.
Разрыв
Подумайте о том, чтобы разрываться как что -то вроде, если у нас есть ценность (состояние), которое A и B читают из этого, но каким -то образом в рендеринге изменяется ценность. B -компонент позже, чем Таким образом, в рендеринге значение в компоненте A составляет 0, а в более новом компоненте (B) значение составляет 1. Мы называем это разрывом; Это означает, что вы видите два разных значения в просмотре из одного точного источника. Это новая и трудно понять реализацию в одновременном режиме React; Для получения дополнительной информации см. это Анкет
Экспериментальный, почему я должен его использовать?
Итак, я подумал об этом, у нас есть два варианта:
- Экспериментальная версия React:
пряжа добавить React@экспериментальный - Последовательная версия
UseMutablesource, вы можете скопировать вставить его из здесь
Я рекомендую второй вариант, потому что он не изменится, и пока хорошо, если у нас нет UseMutablesource В основной версии реагирования.
Контекст без поставщика
Я думаю, что мы достигли того, что привело вас сюда, но подождите, прежде чем все это, не забудьте посмотреть на мой GitHub и Twitter ; Вы увидите там классные вещи и помогите мне с моим учебным путешествием. Итак, начнем.
Некоторые из приведенных ниже кода написаны с помощью TypeScript, поэтому он будет более понятным, даже для людей, которые не знают TypeScript.
Начинать
Сначала нам нужно создать простой глобальный объект, который содержит три свойства:
const globalStore = {
state: { count: 0 },
version: 0,
listeners: new Set<() => any>()
};
Государство: простое значение, такое как значение контекста ReactВерсия: важная часть, которая должна меняться, когда какая -либо часть состояния меняетсяСлушатели: Набор функций, которые мы называем им каждый раз, когда меняем частьгосударство, поэтому мы уведомим их об изменениях
Теперь нам нужно создать изменчивый источник из Globalstore И дайте ему версию, так что это поможет ей сэкономить новые изменения, поэтому мы собираемся получить к нему доступ к ней в GetSnapShot и подписываться ; Мы скоро поговорим об этом.
const globalStoreSource = createMutableSource( globalStore, () => globalStore.version // (store) => store.version (Optional) if you use the consistent and non-experimental version of useMutableSource );
Теперь пришло время поговорить о GetSnapShot ; Короче говоря, это функция, которая UseMutablesource Возвращает возвращаемое значение всякий раз, когда изменение состояния.
const cache = new Map();
const getSnapshot = (store: typeof globalStore) => {
const setState = (
cb: (prevState: typeof store.state) => typeof store.state
) => {
store.state = cb({ ...store.state });
store.version++;
store.listeners.forEach((listener) => listener());
};
if (!cache.has(store.state) || !cache.has(store)) {
cache.clear(); // remove all the old references
cache.set(store.state, [{ ...store.state }, setState]);
// we cache the result to prevent the useless re-renders
// the key (store.state) is more consistent than the { ...store.state },
// because this changes everytime as a new object, and it always going to create a new cache
cache.set(store, store); // check the above if statement, if the store changed completely (reference change), we'll make a new result and new state
}
return cache.get(store.state); // [state, setState]
};
// later: const [state, setState] = useMutableSource(...)
Взгляните на SetState Функция, сначала мы используем CB и передайте его предыдущему состоянию, затем назначьте его возвращенное значение нашему состоянию, затем мы обновляем версию магазина и сообщаем всех слушателей о новом изменении.
Мы использовали оператор спреда ({... store.state}) Потому что мы должны клонировать значение, поэтому мы делаем новую ссылку для нового объекта состояния и отключили прямые мутации.
У нас нет слушатель Тем не менее, как мы можем добавить его? с подписаться функция, посмотрите на это:
const subscribe = (store: typeof globalStore, callback: () => any) => {
store.listeners.add(callback);
return () => store.listeners.delete(callback);
};
Эта функция будет вызвана UseMutablesource В Так что это проходит подписаться два параметра:
Магазин: который является нашим оригинальным магазиномобратный вызов: Это вызовет наш компонент повторно (поUseMutablesource)
Итак, когда UseMutablesource Вызывает подписку, мы собираемся добавить обратный вызов нашим слушателям. Всякий раз, когда что-то меняется в штате ( setState ), мы называем всех наших слушателей, чтобы компонент был повторно рендер. Вот как у нас есть обновленная стоимость каждый раз с UseMutablesource Анкет
Таким образом, вы можете задаться вопросом, мы удалили обратный вызов взамен, ответ таково, что когда компонент намекает, UseMutablesource позвонит subscribe () , или в другом семестре мы называем это Отписаться . Когда он будет удален, мы больше не будем называть бесполезный обратный вызов, который приведет к повторному рендерингу для необедененного (или иногда старого) компонента.
UseContext
Теперь мы достигли конечной линии, не думайте слишком много о названии, мы просто хотели имитировать версию без поставщика контекста React.
export function useContext() {
return useMutableSource(globalStoreSource, getSnapshot, subscribe);
} // returns [state, setState]
Теперь мы можем использовать эту функцию везде, где хотим. Взгляните на этот пример, или, если хотите, вы можете пойти прямо на CodeSandbox .
function Display1() {
const [state] = useContext();
return Display1 component count: {state.count};
}
function Display2() {
const [state] = useContext();
return Display2 component count: {state.count};
}
function Changer() {
const [, setState] = useContext();
return (
);
}
function App() {
return (
);
}
Теперь, когда вы нажимаете кнопку +1, вы можете увидеть красивые изменения без каких -либо Поставщик Анкет
Я надеюсь, что вам понравилась эта статья, и не забудьте поделиться и реакции на мою статью. Если вы хотите мне что -нибудь сказать, скажите мне о Twitter или упомянуть меня где угодно, вы даже можете подписаться на мой Информационный бюллетень Анкет
- Покрытие изображения: эксперимент, Николас Томас, Unsplash
Оригинал: “https://dev.to/aslemammad/react-context-without-provider-usemutablesource-4aph”