useContext 相当于 class 组件中的 static contextType = Context
或者 <Context.Consumer>
, 它写起来比较方便,像是在this.props取值一样,一行代码就可以完成。它接收一个 context 对象(React.createContext
的返回值)并返回该 context 的当前值。当前的 context的值由上层组件中距离当前组件最近的 <Context.Provider>
的 value
属性决定的。当上层组件提供的value
属性发送变化,useContext
会让当前组件重新渲染。
使用
一般我们项目开发中定义的全局信息可以放到context中,比如主题还有统一的样式前缀名称等等,还有也可以作为组件间状态传递使用,实现数据共享, 我们可以吧context看作为React 组件中类似的全局变量的形式。
语法类型定义
// 语法类型定义
interface Context<T> {
Provider: Provider<T>;
Consumer: Consumer<T>;
displayName?: string | undefined;
}
function useContext<T>(context: Context<T>): T;
使用useContext
前必须有定义好的context对象,要让其作为useContext
的参数使用, 并且在使用useContext
的上层某个组件使用了ConfigContext.Provider
传递context的值,如果没有提供值则默认会使用createContext定义时定义的值。当Provider中的value发生变化后所有使用useContext的组件都能获取到最新的value值
interface ConfigContextProps {
prefix: string
};
const ConfigContext = React.createContext<ConfigContextProps>({ prefix: 'ant' });
const Demo: React.FC = () => {
return (
<ConfigContext.Provider value={{prefix: 'avt'}}>
<Child />
</ConfigContext.Provider>
);
}
const Child: React.FC = (props) => {
const { prefix } = useContext<ConfigContextProps>(ConfigContext)
return (
<div>{prefix}</div>
)
}
export default Demo;
useContext使用ConfigContext.Consumer或者定义Child.contextType的方式使用时方便,清晰容易理解。
const Child: React.FC = (props) => {
const { prefix } = useContext<ConfigContextProps>(ConfigContext)
return (
<ConfigContext.Consumer>
{
({ prefix }) => (
<div>{prefix}</div>
)
}
</ConfigContext.Consumer>
)
}
总结
context在许多项目中应用都非常广泛,如redux中的状态共享就是使用context实现的。但是并不是所有的组件间传递状态都要使用context,因为它其实是违背的组件的概念,对组件有入侵性,可能导致组件无法复用。