掌握React基础知识第七章-跨组件通信Context

500 阅读3分钟

2022即将到来,前端发展非常迅速,现在的前端已经不再是写写简单的页面了,伴随着web大前端,工程化越来越火,也出现了很多框架。很多公司也不单单是使用单一的框架了,作为前端开发国内最火的两大框架,都是必须要掌握的。所以,我决定在这疫情肆虐的年底把React学习一下,也为自己将来找工作多一分竞争力...

学习阶段,如有不对之处,欢迎评论区留言,我及时更正

本文已连载,其它章节传送门⬇️

第一章-jsx语法认识

第二章-函数组件和class类组件

第三章-Props和State

第四章-事件处理

第五章-Ref和Refs

第六章-生命周期

第八章-React Hooks

跨组件通信Context

父子组件的通信我们可以通过Props传递,但如果嵌套很多层的组件需要通信,我们需要一层一层传递到后代组件,这使得通信变得异常繁琐,于是React通过订阅Context实现了跨组件的通信,无需一层层传递。

不过使用Context我们需要注意以下几点:

  • 函数组件没有context属性

  • 组件如果订阅了context,会从离自身最近的匹配的Provier中读取当前context值

  • 一个Provider 可以和多个订阅组件有对应关系,多个Provider 也可以嵌套使用,里层覆盖外层数据

  • 当Provider value值发生变化的时候,所有订阅此context的组件都会重新渲染

context的Provider

// 创建Context
const UserContext = React.createContext({
  nickName: '小明',
  userId: 'jd1557834'
});
class Son extends Component {
  static contextType = UserContext
  render() {
    console.log(this.context)
    return (
      <div>
        <p>昵称:{this.context.nickName}</p>
        <p>账号:{this.context.userId}</p>
      </div>
    )
  }
}
class Person extends Component {
  render() {
    return (
      <div>
        <Son></Son>
      </div>
    )
  }
}
class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      nickName: '小红',
      userId: 'jd1557834'
    }
  }
  render() {
    return (
      <div>
        <UserContext.Provider value={this.state}>
          <Person />
        </UserContext.Provider>
      </div>
    )
  }
}

创建App Person Son 三个组件,它们的层级关系为:App >Person >Son 。想要使用Context,首先 我们需要调用React.createContext 创建一个context,可以给一个初始值。每个context都会返回一个Provider 组件 ,供其它后代组件订阅context的变化~把传递数据的组件包裹在Provider 组件内部,此时把我们需要传递的数据放在value属性里。 OK,这时再看我们的后代子孙组件,通过 static 关键字指定此组件的contextType,把我们创建的context赋值给此组件的context,组件内部就可以通过context接收到数据了。

context的Consumer

💡问题:如果子组件是函数组件,没有context属性,怎么办?

function Son() {
  return(
    <UserContext.Consumer>
      {
        value => {
          return(
            <div>
             <p>昵称:{value.nickName}</p>
              <p>账号:{value.userId}</p>
            </div>
          )
        }
      }
    </UserContext.Consumer>
  )
}

context除了Provider还会返回一个Consumer组件,用来解决函数组件没有context属性的问题,我们需要把组件的内容包裹在Consumer 组件内,并在组件内通过箭头函数的入参拿到传递的value,这样我们就可以直接在组件内使用value。

多个context

💡问题:如果我们有多个context需要共享数据怎么办?

创建一个新的context

const MobileContext = React.createContext({
  mobileNumber: 15138994429
})

修改APP根组件

<UserContext.Provider value={this.state}>
	<MobileContext.Provider value={{mobileNumber: 15592899231}}>
	  <Person />
  </MobileContext.Provider>
</UserContext.Provider>

修改son子组件

function Son() {
  return(
    <UserContext.Consumer>
      {
        value => {
          return(
            <MobileContext.Consumer>
              {
                them => {
                  return(
                    <div>
                      <p>昵称:{value.nickName}</p>
                      <p>账号:{value.userId}</p>
                      <p>手机号码:{them.mobileNumber}</p>
                    </div>
                  )
                }
              }
            </MobileContext.Consumer>
          )
        }
      }
    </UserContext.Consumer>
  )
}

多个context需要提供的话,就会变得异常繁琐,嵌套层级过多,代码阅读性也变得很差了