hook之useContext

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组件造成影响。

猜你喜欢

转载自blog.csdn.net/m0_59345890/article/details/127326984