持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情
前言
前面2篇文章我们讲了react的useState,和useEffect
文章地址:
咱们今天来看看react的其它常用hook,useContext。
Context
在讲useContext之前,我们要先来讲讲Context,因为它们是配合使用的。
Context是解决组件之间数据共享的,同理useContext也是解决组件数据通信的hook。
正常一般组件数据通信通过props就能解决,但是如果层级过深,props就得一直传下去,不方便。
所以就有了Context。这个不管你层级多深,只要你在顶层定义了共享的数据,在哪层的子孙组件都能访问到这个共享数据。
下面这个例子,如果正常使用props,那么就要一层一层从CompA传到CompD。
function CompA () {
const [text] = useState('答案cp3')
return (
<CompB text={text}></CompB>
)
}
function CompB (props) {
return (
<CompC text={props.text}></CompC>
)
}
function CompC (props) {
return (
<CompD text={props.text}></CompD>
)
}
function CompD (props) {
return (
<div>{props.text}</div>
)
}
那么来看看如果使用Context该怎么写?
要先定义context对象,括号内是初始值。
const textContext = React.createContext('')
然后把textContext导出标签 Provider和Consumer,用Provider标签包裹着CompB。 这时候可以提供value,会覆盖createContext定义的初始值。
如果不使用Provider标签,则createContext的初始值会生效。
接着使用Consumer使用包裹着CompD, 这个Consumer是在函数组件使用的。内部返回一个函数,参数就是共享的value。
const { Provider, Consumer } = textContext
function CompA () {
return (
<Provider value={'答案cp3'}>
<CompB></CompB>
</Provider>
)
}
function CompB () {
return (
<CompC></CompC>
)
}
function CompC () {
return (
<CompD></CompD>
)
}
function CompD () {
return (
<Consumer>
{value => value}
</Consumer>
)
}
这样实现,CompB和CompC就不用一层一层写props了。
如果你使用的是class组件,则可以不使用Consumer,代码如下:
class CompD extends React.Component {
static contextType = textContext
render () {
return (
<div>{this.context}</div>
)
}
}
要定义个静态对象contextType, render函数的this.context就是定义的value。
上面说的只是获取,那怎么修改呢?
如果你要修改context的内容,你定义个方法,传入然后对应的组件里调用,就可以修改了。
代码如下:
function CompA () {
const [text, setText] = useState('hello world')
return (
<Provider value={{ text, setText }}>
<CompD></CompD>
</Provider>
)
}
class CompD extends React.Component {
static contextType = textContext
clickFn = () => {
this.context.setText('答案cp3')
}
render () {
return (
<div onClick={this.clickFn}>{this.context.text}</div>
)
}
}
好,context的知识已经学完了。下面来看看useContext
useContext
useContext其实相当于上面的说的Consumer或者静态方法contextType。
使用了useContext就不用在函数组件中使用Consumer了。
返回的是顶层定义的数据。
我用上面的例子改写一下:
function CompA () {
const [text, setText] = useState('hello world')
return (
<Provider value={{ text, setText }}>
<CompD></CompD>
</Provider>
)
}
function CompD () {
const { text, setText } = useContext(textContext)
return (
<div onClick={() => setText('答案cp3')}>{text}</div>
)
}
这样看起来useContext是不是更简洁一些?