内容目录
businessfragmentation
useContext
useContext 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。设计的目的就是解决组件树间数据传递的问题。用法
import React,{useContext} from 'react'
const MyThemeContext = React.createContext({theme: 'light'}); // 创建一个上下文
function App () {
return (
<MyThemeContext.Provider value={{theme: 'light'}}>
<MyComponent />
</MyThemeContext.Provider>
)
}
function MyComponent() {
const themeContext = useContext(MyThemeContext); // 使用上下文
return (<div>{themeContext.theme}</div>);
}
参数
入参- context:是 createContext 创建出来的对象,他不保持信息,他是信息的载体。声明了可以从组件获取或者给组件提供信息。
- 返回传递的Context的值,并且是只读的。如果 context 发生变化,React 会自动重新渲染读取 context 的组件
基本用法
主题切换
首先我们先通过createContext创建一个上下文,然后通过createContext创建的组件包裹组件,传递值。 被包裹的组件,在任何一个层级都是可以获取上下文的值,降低组件之间的耦合度 使用的方式就是通过useContext这个hook,然后传入上下文,就可以获取到上下文的值。- 18版本演示
import React, { useContext, useState } from 'react';
// 创建上下文
const ThemeContext = React.createContext<ThemeContextType>({} as ThemeContextType);
// 定义上下文类型
interface ThemeContextType {
theme: string;
setTheme: (theme: string) => void;
}
const Child = () => {
// 获取上下文
const themeContext = useContext(ThemeContext);
const styles = {
backgroundColor: themeContext.theme === 'light' ? 'white' : 'black',
border: '1px solid red',
width: 100 + 'px',
height: 100 + 'px',
color: themeContext.theme === 'light' ? 'black' : 'white'
}
return <div>
<div style={styles}>
child
</div>
</div>
}
const Parent = () => {
// 获取上下文
const themeContext = useContext(ThemeContext);
const styles = {
backgroundColor: themeContext.theme === 'light' ? 'white' : 'black',
border: '1px solid red',
width: 100 + 'px',
height: 100 + 'px',
color: themeContext.theme === 'light' ? 'black' : 'white'
}
return <div>
<div style={styles}>
Parent
</div>
<Child />
</div>
}
function App() {
const [theme, setTheme] = useState('light');
return (
<div>
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>切换主题</button>
<ThemeContext.Provider value={{ theme, setTheme }}>
<Parent />
</ThemeContext.Provider>
</div >
);
}
export default App;
- 19版本演示
import React, { useContext, useState } from 'react';
const ThemeContext = React.createContext<ThemeContextType>({} as ThemeContextType);
interface ThemeContextType {
theme: string;
setTheme: (theme: string) => void;
}
const Child = () => {
const themeContext = useContext(ThemeContext);
const styles = {
backgroundColor: themeContext.theme === 'light' ? 'white' : 'black',
border: '1px solid red',
width: 100 + 'px',
height: 100 + 'px',
color: themeContext.theme === 'light' ? 'black' : 'white'
}
return <div>
<div style={styles}>
child
</div>
</div>
}
const Parent = () => {
const themeContext = useContext(ThemeContext);
const styles = {
backgroundColor: themeContext.theme === 'light' ? 'white' : 'black',
border: '1px solid red',
width: 100 + 'px',
height: 100 + 'px',
color: themeContext.theme === 'light' ? 'black' : 'white'
}
return <div>
<div style={styles}>
Parent
</div>
<Child />
</div>
}
function App() {
const [theme, setTheme] = useState('light');
return (
<div>
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>切换主题</button>
<ThemeContext value={{ theme, setTheme }}>
<Parent />
<ThemeContext>
</div >
);
}
注意事项
-
使用 ThemeContext 时,传递的key必须为
value
// 🚩 不起作用:prop 应该是“value”
<ThemeContext theme={theme}>
<Button />
</ThemeContext>
// ✅ 传递 value 作为 prop
<ThemeContext value={theme}>
<Button />
</ThemeContext>
- 多 个相同Context嵌套使用时,若Context value值相同则会覆盖
-
从接收到不同的
value
开始,React 自动重新渲染使用了该特定 context 的所有子级。先前的值和新的值会使用 Object.is 来做比较。 - 使用 memo 来跳过重新渲染并不妨碍子级接收到新的 context 值。
-
如果你的构建系统在输出中产生重复的模块(可能发生在符号链接中),这可能会破坏 context。通过 context 传递数据只有在用于传递 context 的
SomeContext
和用于读取数据的SomeContext
是完全相同的对象时才有效,这是由===
比较决定的。
const ThemeContext = React.createContext({theme: 'light'});
function App() {
return (
<ThemeContext value={{theme: 'light'}}>
<ThemeContext value={{theme: 'dark',is:false}}> {/* 覆盖了上面的值 */}
<Parent />
</ThemeContext>
</ThemeContext>
)
}