Хитрость, позволяющая не присматривать за типами контекста, проста!
Если вы используете контекстный API, то одной из проблем является присмотр за его типами.
Другой вариант — необходимость многократного импорта, чтобы использовать его, когда он вам нужен.
С помощью этого примера мы решаем обе проблемы и делаем использование React Context API быстрым и простым.
Скопируйте, вставьте, а затем просто замените все слова «пример» на то, что вам нужно назвать, и все готово.
(После этого будет полностью прокомментированная версия.)
import { createContext, useCallback, useContext, useDeferredValue, useMemo, useState, } from 'react'; function useContextValue(init: number = 0) { const [state, setState] = useState(init); const doubleValue = state * 2; const defferedStringValue = useDeferredValue(state.toString()); const reset = useCallback(() => { setState(init); }, []); const value = useMemo( () => ({ state, doubleValue, defferedStringValue, reset, }), [ state, doubleValue, defferedStringValue, reset, ], ); return value; } type ExampleContext = ReturnType; const Context = createContext (null!); Context.displayName = 'ExampleContext'; export function ExampleContextProvider({ children, initValue = 0, }: { children: React.ReactNode; initValue?: number; }) { const value = useContextValue(initValue); return {children} ; } export function useExample() { const value = useContext(Context); if (!value) { throw new Error('useExample must be used within a ExampleContextProvider'); } return value; }
import { createContext, useCallback, useContext, useDeferredValue, useMemo, useState, } from 'react'; /** * We create a custom hook that will have everything * that would usually be in the context main function * * this way, we can use the value it returns to infer the * type of the context */ function useContextValue(init: number = 0) { // do whatever you want inside const [state, setState] = useState(init); const doubleValue = state * 2; const defferedStringValue = useDeferredValue(state.toString()); // remember to memoize functions const reset = useCallback(() => { setState(init); }, []); // and also memoize the final value const value = useMemo( () => ({ state, doubleValue, defferedStringValue, reset, }), [ state, doubleValue, defferedStringValue, reset, ], ); return value; } /** * Since we can infer from the hook, * no need to create the context type by hand */ type ExampleContext = ReturnType; const Context = createContext (null!); Context.displayName = 'ExampleContext'; export function ExampleContextProvider({ children, /** * this is optional, but it's always a good to remember * that the context is still a react component * and can receive values other than just the children */ initValue = 0, }: { children: React.ReactNode; initValue?: number; }) { const value = useContextValue(initValue); return {children} ; } /** * We also export a hook that will use the context * * this way, we can use it in other components * by importing just this one hook */ export function useExample() { const value = useContext(Context); /** * this will throw an error if the context * is not used within the provider * * this also avoid the context being "undefined" */ if (!value) { throw new Error('useExample must be used within a ExampleProvider'); } return value; }
Вот и все. Контекстный API проще и сложнее, чем следовало бы, но это мощный инструмент для тех случаев, когда его необходимо использовать.
Просто помните, что React Context API — это не Redux (или другие менеджеры состояний), и вам не следует помещать в него все состояние приложения.
Ну, можно, но это может вызвать ненужные проблемы.
Это было написано с учетом React
Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.
Copyright© 2022 湘ICP备2022001581号-3