解决问题:在较深的组件树中如何进行数据的传递
react中的数据在父子组件中一般以props形式传递,如果父组件要把某个数据传递给孙子或者重孙子组件,就要经过子组件层层传递,比较麻烦。为此引入context全局上下文,来实现数据跨组件共享
🌰举例:设置主题色:黑色/白色
生产侧代码:useTheme.tsx文件⬇️
// 1 创建主题色上下文
const ThemeContext = React.createContext(undefined);
ThemeContext.displayName = 'ThemeContext';
// 2 创建Provider,同时设定value
// context会根据引用标识决定何时进行渲染,所以一个陷阱🪤,provider的父组件重新渲染时,可能会在consumers组件中触发意外的渲染
// 为了防止这种情况,需要将value状态提升到父节点的state中
const ThemeProvider = (children) => {
const [theme, setTheme] = useState('light');
return <ThemeContext.Provider value={theme, setTheme}>
{ children }
</ThemeContext.Provider>
}
// 3 创建hooks
const useTheme = () => {
const context = useContext(themeContext);
if(!context){
throw new Error ('useTheme必须在ThemeProvider中使用')
}
return context;
}
消费侧代码:
首先作为Provider的子组件使用
<Themeprovider>
<ThemeBar/>
</Themeprovider>
其中ThemeBar中可以拿到全局数据theme
import React from 'react';
// theme变化,ThemeBar就重新渲染,所以不建议把很多属性耦合进入同一个Context中
// 要把经常变化的和不经常变化的分开,例如:ThemeContext就负责Theme
const ThemeBar = () => {
const {theme, setTheme} = useTheme();
return <div onClick={()=>setTheme('dark')}>{theme}<div>
}
当Provider的value变化时,内部所有消费组件都会重新渲染,并且useContext的传播不会受制于shouldComponentUpdate函数,所以父亲组件用了memo,但子组件是context的消费组件,当value变化时,也会重新渲染