「回顾 2022,展望 2023,我正在参与2022 年终总结征文大赛活动」
概念
-
共享那些对于一个组件树而言是“全局”的数据,主题,用户信息,路由,状态管理
-
多个 Provider 嵌套使用,里层的会覆盖外层的数据
-
Provider 的
value值发生变化时,它内部的所有消费组件都会重新渲染 -
即使祖先使用 React.memo 也会重新渲染
-
只是想避免层层传递一些属性,使用组件组合(component composition)
-
props 多个层级传递,替换为 props 传递整个组件
-
传递多个子组件,甚至会为这些子组件(children)封装多个单独的“接口(slots)
-
需要将子组件和直接关联的父组件解耦
-
-
使用
- 创建 一个 context。
- 在需要数据的组件内 使用 刚刚创建的 context。
- 在指定数据的组件中 提供 这个 context。
const MyContext = createContext(defaultValue);
<MyContext.Provider value={/* 某个值 */}></MyContext.Provider;
MyContext.displayName = 'MyDisplayName';
重渲染组件的开销较大,使用 memoization 优化
-
拆分 context,从原有 context 内部拆分为另一 context
function Button() { let theme = useContext(ThemeContext); // The rest of your rendering logic return <ExpensiveTree className={theme} />; } -
拆分组件,接收 context 组件拆分为两个组件,父组件接收 context 传递给子组件,子组件使用 memo
function Button() { let appContextValue = useContext(AppContext); let theme = appContextValue.theme; // Your "selector" return <ThemedButton theme={theme} /> } const ThemedButton = memo(({ theme }) => { // The rest of your rendering logic return <ExpensiveTree className={theme} />; }); -
组件内部 return 一个 useMemo 函数,指定依赖列表
function Button() { let appContextValue = useContext(AppContext); let theme = appContextValue.theme; // Your "selector" return useMemo(() => { // The rest of your rendering logic return <ExpensiveTree className={theme} />; }, [theme]) }
结合使用 Reducer 和 Context
- 创建 context
- 将 state 和 dispatch 放入 context
- 在组件树的任何地方 使用 context
- 将相关逻辑迁移到一个文件当中
import { createContext, useContext, useReducer } from 'react';
const TasksContext = createContext(null);
const TasksDispatchContext = createContext(null);
export function TasksProvider({ children }) {
const [tasks, dispatch] = useReducer(
tasksReducer,
initialTasks
);
return (
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider value={dispatch}>
{children}
</TasksDispatchContext.Provider>
</TasksContext.Provider>
);
}
export function useTasks() {
return useContext(TasksContext);
}
export function useTasksDispatch() {
return useContext(TasksDispatchContext);
}
function tasksReducer(tasks, action) {
switch (action.type) {
case 'added': {
return [...tasks, {
id: action.id,
text: action.text,
done: false
}];
}
case 'changed': {
return tasks.map(t => {
if (t.id === action.task.id) {
return action.task;
} else {
return t;
}
});
}
case 'deleted': {
return tasks.filter(t => t.id !== action.id);
}
default: {
throw Error('Unknown action: ' + action.type);
}
}
}
const initialTasks = [
{ id: 0, text: 'Philosopher’s Path', done: true },
{ id: 1, text: 'Visit the temple', done: false },
{ id: 2, text: 'Drink matcha', done: false }
];
注意
- 不要传递对象给
value undefined传递给 Provider 的 value 时,消费组件的defaultValue不会生效- 只有当组件所处的树中没有匹配到 Provider 时,其
defaultValue参数才会生效