• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

任意组件传值-React.createContext的使用

武飞扬头像
Xavier-萧
帮助1

1.React.createContext的使用场景

  • 在开发中,比较常间的数据传递方式是通过props属性自上而下(由父到子)进行传递。
  • 但是对于有一些场景:比如一些数据需要在多个组件中进行共享(地区偏好、UI主题、用户登录状态、用户信息等)。
  • 如果我们在顶层App中定义这些信息,之后一层层传递下去,那么对于一些中层不需要数据的组件来说,是一种冗余的操作。
  • 我们来看一个例子
import React, { Component } from "react";
function ProfileHeader(props) {//子组件
  return (
    <div>
      <h2>用户昵称:{props.nickName}</h2>
      <h2>用户等级:{props.level}</h2>
    </div>
  );
}

class Profile extends Component {//父组件-包裹子组件
  render() {
    return (
      <div>
        <ProfileHeader {...this.props} />
        <ul>
          <li>内容1</li>
        </ul>
      </div>
    );
  }
}

class App extends Component {//祖父组件
  constructor(props) {
    super(props);
    this.state = {
      nickName: "张三",
      level: 9,
    };
  }
  render() {
    return(
      <div>
        <Profile nickName={this.state.nickName} level={this.state.level} />
        <p>我是段落</p>
      </div>
    );
  }
}
export default App;
学新通
  • 从例子代码可知,从App组件中传递了两个属性,经由Profile组件转发到了ProfileHeader组件,这个就是一个标准的父子组件嵌套传值的方式,但是也很明显的看出Profile组件,并没有用到那两个属性,但是数据确确实实经由了Profile组件。
    • React提供了一个APIContext
    • Context提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递props
    • Context设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言;

2.Context相关的API的使用方法

  • 先定义,再供值,再消费
  • 定义:React.createContext
	const Context = React.createContext(defaultValue);
  • 创建一个需要共享的Context对象:返回值是一个组件
    • 如果一个组件消费了Context,那么这个组件会从离自身最近的那个匹配的Context.Provider中读取到当前的Context值;
    • defaultValue是组件在顶层查找过程中没有找到对应的Context.Provider,那么就使用默认值
  • 供应:Context.Provider
	<Context.Provider value={/* 某个值 */}>
  • 每个Context对象都会返回一个Provider React组件,它允许消费组件订阅Context的变化:
    • Context.Provider接收一个value属性,传递给消费组件;
    • 一个Context.Provider可以和多个消费组件有对应关系;
    • 多个Context.Provider也可以嵌套使用,里层的会覆盖外层的数据;
  • Context.Providervalue发生变化的时候,它内部的所有消费组件都会重新渲染;

2.1useContext-只限于函数组件消费-推荐

  • 函数式组件就用useContext的方案-简洁明了
import React, { Component, useContext } from "react";
let UserInfo=React.createContext({
  nickName:'张三',
  level:1
})
let Theme=React.createContext('红色')
function ProfileHeader() {//函数式组件就用useContext的方案-简洁明了
  let userInfo=useContext(UserInfo)
  console.log(userInfo);//{nickName: '张三', level: 1}
  let theme=useContext(Theme)
  console.log(theme);//中国红
  return (
    <div>
      <h2>主题颜色:{theme}</h2>
      <h2>用户昵称:{userInfo.nickName}</h2>
      <h2>用户等级:{userInfo.level}</h2>
    </div>
  );
}

class Profile extends Component {//父组件-包裹子组件
  render() {
    return (
      <div>
        <ProfileHeader/>
        <ul>
          <li>内容1</li>
        </ul>
      </div>
    );
  }
}

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      nickName: "张三",
      level: 9,
    };
  }
  render() {
    return(
      <div>
        {/* 注意点:如果包裹了组件,value必须存在值,它不会去读默认值的 */}
        <UserInfo.Provider value={{nickName:'李四',level:9}} >
          <Theme.Provider value="中国红">
            <Profile/>
          </Theme.Provider>
        </UserInfo.Provider>
        <p>我是段落</p>
      </div>
    );
  }
}
export default App;
学新通

2.2Context.Consumer函数式组件/类式组件-不推荐

2.2.1函数式组件

import React, { Component, useContext } from "react";
import { Fragment } from "react/cjs/react.production.min";
let UserInfo=React.createContext({
  nickName:'张三',
  level:1
})
let Theme=React.createContext('红色')
function ProfileHeader() {
  return (
    <div>
      <UserInfo.Consumer>
        {
          userInfo=>{
            console.log(userInfo);//{nickName: '李四', level: 9}
            return <Theme.Consumer>
              {
                theme=>{
                  console.log(theme);//中国红
                  return (
                    <Fragment>
                      <h2>主题颜色:{theme}</h2>
                      <h2>用户昵称:{userInfo.nickName}</h2>
                      <h2>用户等级:{userInfo.level}</h2>
                    </Fragment>
                  )
                }
              }
            </Theme.Consumer>
          }
        }
      </UserInfo.Consumer>
    </div>
  );
}

class Profile extends Component {
  render() {
    return (
      <div>
        <ProfileHeader/>
        <ul>
          <li>内容1</li>
        </ul>
      </div>
    );
  }
}

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      nickName: "张三",
      level: 9,
    };
  }
  render() {
    return(
      <div>
        {/* 注意点:如果包裹了组件,value必须存在值,它不会去读默认值的 */}
        <UserInfo.Provider value={{nickName:'李四',level:9}} >
          <Theme.Provider value="中国红">
            <Profile/>
          </Theme.Provider>
        </UserInfo.Provider>
        <p>我是段落</p>
      </div>
    );
  }
}
export default App;
学新通

2.2.2类式组件

import React, { Component, useContext,Fragment } from "react";
let UserInfo = React.createContext({
  nickName: "张三",
  level: 1,
});
let Theme = React.createContext("红色");
class ProfileHeader extends Component{
  render() {
    return (
      <div>
        <UserInfo.Consumer>
          {(userInfo) => {
            console.log(userInfo); //{nickName: '李四', level: 9}
            return (
              <Theme.Consumer>
                {(theme) => {
                  console.log(theme); //中国红
                  return (
                    <Fragment>
                      <h2>主题颜色:{theme}</h2>
                      <h2>用户昵称:{userInfo.nickName}</h2>
                      <h2>用户等级:{userInfo.level}</h2>
                    </Fragment>
                  );
                }}
              </Theme.Consumer>
            );
          }}
        </UserInfo.Consumer>
      </div>
    );
  }
}

class Profile extends Component {
  render() {
    return (
      <div>
        <ProfileHeader />
        <ul>
          <li>内容1</li>
        </ul>
      </div>
    );
  }
}

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      nickName: "张三",
      level: 9,
    };
  }
  render() {
    return (
      <div>
        {/* 注意点:如果包裹了组件,value必须存在值,它不会去读默认值的 */}
        <UserInfo.Provider value={{ nickName: "李四", level: 9 }}>
          <Theme.Provider value="中国红">
            <Profile />
          </Theme.Provider>
        </UserInfo.Provider>
        <p>我是段落</p>
      </div>
    );
  }
}
export default App;
学新通

2.3Class.contextType值只限于类组件-不推荐

  • 挂载在class上的静态属性contextType会被重赋值为一个由React.createContext()创建的Context对象:
  • 这能让你使用this.context来消费最近Context上的那个值;
  • 你可以在任何生命周期中访问到它,包括render函数中;
  • 缺点:只能接一个React.createContext组件的value
import React, { Component, useContext,Fragment } from "react";
let UserInfo = React.createContext({
  nickName: "张三",
  level: 1,
});
let Theme = React.createContext("红色");
class ProfileHeader extends Component {
  render() {
    console.log(this.context);//{nickName: '李四', level: 9}
    return (
      <div>
        <h2>用户昵称:{this.context.nickName}</h2>
        <h2>用户等级:{this.context.level}</h2>
      </div>
    );
  }
  // 缺点就是只能接一个React.createContext组件的value
  static contextType = UserInfo;
}

class Profile extends Component {
  render() {
    return (
      <div>
        <ProfileHeader />
        <ul>
          <li>内容1</li>
        </ul>
      </div>
    );
  }
}

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      nickName: "张三",
      level: 9,
    };
  }
  render() {
    return (
      <div>
        <UserInfo.Provider value={{ nickName: "李四", level: 9 }}>
          <Theme.Provider value="中国红">
            <Profile />
          </Theme.Provider>
        </UserInfo.Provider>
        <p>我是段落</p>
      </div>
    );
  }
}
export default App;
学新通

2.4什么时候使用默认值defaultValue呢?

<UserContext.Provider value={{ nickname: "why", level: 99 }}></UserContext.Provider>
<Profile />

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhibfbbi
系列文章
更多 icon
同类精品
更多 icon
继续加载