使用绝对没有问题useContext
直接在组件中。然而,它强制必须使用上下文值的组件知道要使用什么上下文。
如果您希望在应用程序中有多个组件使用 TodoProvider 上下文,或者您的应用程序中有多个上下文,则可以使用自定义挂钩来简化它
使用上下文时还必须考虑的另一件事是,您不应该在每个渲染上创建一个新对象,否则所有正在使用的组件context
即使没有任何改变,也会重新渲染。为此,您可以使用useMemo
hook
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)}</pre>
</div>
);
};
工作演示 https://codesandbox.io/s/w7w5485xxw
EDIT:
Since getTodos
只是一个不能改变的函数,它使得
使用它作为更新参数的意义useMemo
?
通过才有意义getTodos
如果 getTodos 方法正在更改并且在功能组件内被调用,则到 useMemo 中的依赖项数组。通常你会使用以下方法来记住该方法useCallback
因此,它不会在每个渲染上创建,但仅当其封闭范围的任何依赖项发生更改以更新其词法范围内的依赖项时才创建。现在,在这种情况下,您需要将其作为参数传递给依赖项数组。
但就您的情况而言,您可以省略它。
另外你将如何处理初始效果。说如果你要打电话
当提供商安装时, useEffect 挂钩中的“getTodos”?你能记住吗
那个电话也是如此?
您只需在初始安装时调用的 Provider 中产生一个效果
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>;
};