Если вы объявляете объект в значении контекста Provider, любые потребители контекста всегда будут перерисовывать, если провайдер повторно рендерит, потому что каждый раз, когда провайдер повторно рендерит объект внутри value
, объявляется повторно.
return (
<Provider value={{ /* declared object */ }}>{children}</Provider>
);
Хороший поставщик value
Шаблон
Ниже приведен хороший шаблон, поскольку store
изменится только при вызове setStore
.
// ParentComponent.js
function ParentComponent() {
const [store, setStore] = useState({ bool: false });
return (
<Context.Provider value={store}>
<button onClick={() => setStore({ ...store, n: { bool: !store.n.bool } })}>
Switch Bool
</button>
<ContextConsumingComponent />
</Context.Provider>
);
}
// ContextConsumingComponent.js
function ContextConsumingComponent() {
const store = useContext(Context);
console.log('Will only run re-render if the `Switch Bool` button is clicked in parent.');
return <p>{JSON.stringify(context.bool)}</p>;
}
// Avoid re-renders if props haven't changed.
export default React.memo(ContextConsumingComponent);
Плохой поставщик value
Pattern
Это плохой шаблон, потому что <Provider value={{}} />
прослушивает изменения для включающего объекта, а не сами ссылки store
и setStore
. Реальность такова, что мы все равно хотим действительно слушать store
.
// ParentComponent.js
function ParentComponent() {
const [store, setStore] = useState({ bool: false });
return (
<Context.Provider value={{ store, setStore }}>
<button onClick={() => setStore({ ...store, n: { bool: !store.n.bool } })}>
Switch Bool
</button>
<ContextConsumingComponent />
</Context.Provider>
);
}
Вопрос:
Я хотел бы иметь возможность использовать setStore
в моем контексте потребления компоненты, и я хотел бы понять, как другие люди подходят к этому. Я полагаю, что у меня есть возможность выбора двух провайдеров, но мне интересно посмотреть, как к этому подойдут другие, и если я пропустил любые ±.
Опция двух провайдеров: store
и dispatch
// Two Providers
function ParentComponent() {
const [store, setStore] = useState({ bool: false });
return (
<Store.Provider value={store}>
<Dispatch.Provider value={setStore}>
<button onClick={() => setStore({ ...store, n: { bool: !store.n.bool } })}>
Switch Bool
</button>
<ContextConsumingComponent />
</Dispatch.Provider>
</Store.Provider>
);
}