Нет абсолютно никаких проблем с использованием useContext
непосредственно в компоненте. Однако он заставляет компонент, который должен использовать значение контекста, знать, какой контекст использовать.
Если у вас есть несколько компонентов в приложении, где вы хотите использовать контекст TodoProvider, или у вас есть несколько контекстов в вашем приложении, вы немного упростите его с помощью пользовательского хука
Также еще одна вещь, которую вы должны учитывать при использовании контекста, это то, что вы не должны создавать новый объект при каждом рендеринге, в противном случае все компоненты, которые используют context
, будут перерисовываться, даже если ничего не изменилось бы. Для этого вы можете использовать useMemo
hook
<code>const Context = React.createContext<{ todos: any; fetchTodos: any }>(undefined);
export const TodosProvider: React.FC<any> = ({ children }) => {
const [state, dispatch] = useReducer(reducer, null, init);
const context = useMemo(() => {
return {
todos: state.todos,
fetchTodos: async id => {
const todos = await getTodos(id);
console.log(id);
dispatch({ type: "SET_TODOS", payload: todos });
}
};
}, [state.todos, getTodos]);
return <Context.Provider value={context}>{children}</Context.Provider>;
};
const getTodos = async id => {
console.log(id);
const response = await fetch(
"https://jsonplaceholder.typicode.com/todos/" + id
);
return await response.json();
};
export const useTodos = () => {
const todoContext = useContext(Context);
return todoContext;
};
export const Todos = ({ id }) => {
const { todos, fetchTodos } = useTodos();
useEffect(() => {
if (fetchTodos) fetchTodos(id);
}, [id]);
return (
<div>
<pre>{JSON.stringify(todos)}
);
};
Рабочая демоверсия
EDIT:
Поскольку getTodos
- это просто функция, которая не может измениться, делает ли она
смысл использовать это как аргумент обновления в useMemo
?
Имеет смысл передать getTodos
в массив зависимостей в useMemo, если метод getTodos изменяется и вызывается внутри функционального компонента. Часто вы запоминаете метод, используя useCallback
, чтобы он не создавался при каждом рендеринге, а только в том случае, если какая-либо его зависимость от включаемой области изменяется, чтобы обновить зависимость в его лексической области. Теперь в таком случае вам нужно будет передать его в качестве параметра в массив зависимостей.
Однако в вашем случае вы можете его опустить.
Также, как бы вы справились с начальным эффектом. Скажи, если ты должен был позвонить
`getTodos´ в использовании Перехватить эффект при монтировании провайдера? Не могли бы вы запомнить
что за звонок?
Вы бы просто имели эффект внутри провайдера, который вызывается при первоначальном монтировании
export const TodosProvider: React.FC<any> = ({ children }) => {
const [state, dispatch] = useReducer(reducer, null, init);
const context = useMemo(() => {
return {
todos: state.todos,
fetchTodos: async id => {
const todos = await getTodos(id);
console.log(id);
dispatch({ type: "SET_TODOS", payload: todos });
}
};
}, [state.todos]);
useEffect(() => {
getTodos();
}, [])
return <Context.Provider value={context}>{children}</Context.Provider>;
};