useContext这个hook,我们通过翻译就可以大致知道它的用途,译为使用上下文。context上下文我们在前面就已经使用过了,它是一种用于跨组件之间的传值的技术。
我们学过Context,再来学习useContext这个hook就会变得简单很多。
useContex的作用
一句话来说,就是获取当前引入组件的上下文对象。
useContex的写法
const ctx=useContext(参数)
//useContext只接收一个参数,为我们引入的由React.createContext函数生成的一个上下文对象;
其返回值就是这个上下文对象provider时提供的数据;
注意:一旦在某个组件里面使用了useContext这就相当于该组件订阅了这个context上下文对象的变化,当context值发生变化时,使用到该context的子组件就会被触发重渲染,且它们会拿到context的最新值。
思考为什么要引入useContex?
我们写一个例子:
先定义一个context上下文对象:
import React from 'react'
let myctx=React.createContext()
export default myctx;
在父组件中提供数据:
import React,{useState,useEffect} from 'react'
import Myctx from './myctx'
import Box4 from './Box4'
function App() {
let [obj,setObj]=useState({a:1,b:2})
return (
<div className="App">
<Myctx.Provider value={obj}>
<Box4></Box4>
</Myctx.Provider>
</div>
);
}
在子组件中获取数据:
import React from 'react'
import Myctx from './myctx'
export default function Box4() {
return (
<div>
<Myctx.Consumer>
{
(data)=>{
return (
<div>
box4----------------
<div>{data.a}</div>
<div>{data.b}</div>
</div>
)
}
}
</Myctx.Consumer>
</div>
)
}
在Box4中确确实实获取到了app组件提供的数据,但是只能在在模板中操作数据,不能在外部做一些操作,因此提供了useContext让我们可以在模板外获取到父组件提供的数据。
在Box4组件中使用useContext,改进代码:
import React from 'react'
import Myctx from './myctx'
export default function Box4() {
let obj=useContext(Myctx)
console.log(obj);
return (
<div>
<Myctx.Consumer>
{
(data)=>{
return (
<div>
box4----------------
<div>{data.a}</div>
<div>{data.b}</div>
</div>
)
}
}
</Myctx.Consumer>
</div>
)
}
可以在控制台看到接受的数据:
解决使用useContext()时产生的无效渲染
我们在app组件中能够传数据,也可以把该属性的修改方法也传递过去,如:
let [obj,setObj]=useState({a:1,b:2})
---------------------------------------------
<Myctx.Provider value={[obj,setObj]}>
<Box4></Box4>
</Myctx.Provider>
在Box4中接收,
let [obj,setObj]=useContext(Myctx)
即我们可以在Box4中修改父组件提供的数据,如:
import React, { useContext } from 'react'
import Myctx from './myctx'
export default function Box4() {
let [obj,setObj]=useContext(Myctx)
// console.log(obj,setObj);
obj.a=11
setObj({...obj})
return (
<div>
{obj.a}
</div>
)
}
通过useContext我们更加方便的获取context对象的数据,但是实际开发中我们可能会把很多不同的数据放在同一个context里面,而不同的子组件可能只关心这个context的某一部分数据,当context里面的任意值发生变化的时候,无论这些组件用不用到这些数据它们都会被重新渲染,这可能会造成一些性能问题.
就比如现在我在Box4中,只用到了提供的对象的a属性,但是当我修改b属性时Box4组件也会从新渲染。
这里提供两种解决无效渲染的方法
1、拆分Context
这个方法是最被推荐的做法,和useState一样,我们可以将不需要同时改变的context拆分成不同的context,让它们的职责更加分明,这样子组件只会订阅那些它们需要订阅的context从而避免无用的重渲染。
比如我们把obj拆分为两个对象,{a:1,b:2}=>{a:1}、{b:2}
然后分别创建两个上下文存储,
actx上下文:
import React from 'raeact'
let actx=React.createContext()
export default actx;
bctx上下文:
import React from 'raeact'
let bctx=React.createContext()
export default bctx;
在提供数据时,要同时提供两个上下文的写法采用嵌套写法:
<Actx.Provider value={[obj,changeObj]}>
<Bctx.Provider value={[car,changecar]}>
<Box4></Box4>
</Bctx.Provider>
</Actx.Provider>
即在box4中获取时,只接收Actx就行了,当其它组件中接收Bctx修改b的值,box4组件不会受到影响。
2、可以使用useMemo来优化
useMemo可以缓存任何类型的数据,我们将整个组件函数缓存起来,将组件中所使用到的数据设置为依赖项,只有当所依赖的数据发生改变时才从新渲染。
如:
import React,{useContext,useMemo} from 'react'
import Box2 from "./Box2.jsx"
import userctx from './ctx/userctx.jsx'
function MyMemoBox2(){
let [user,changeuser]=useContext(userctx)
let Box1=()=>{
return (<div>
<div>{user.user.a}</div>
<Box2></Box2>
</div>)
}
return useMemo(Box1,[user.user])
}
export default MyMemoBox2
即只有当user中的user发生改变时才会从新渲染该组件,在其它使用该上下文的组件中修改了user的其它属性不会对Box1组件造成影响。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)