React实现跨组件通讯

以前可以使用一层一层的往下传递,这种可以解决需求,

1.父组件往孙子组件传值:

App.js

import React, { Component } from 'react'
import Profile from './Profile'

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      nikename:"coderhzc",
      level:88
    }
  }
  render() {
    const {nikename,level} = this.state
    return (
      <div>
        <Profile nikename={nikename} level={level}/>
      </div>
    )
  }
}

profile.js文件(注意是函数组件)

import React from 'react';
import ProfileHeader from './ProfileHeader';

export default function Profile(props) {
  // 从父组件传递过来的
  console.log(props,"profile");
  return (
    <div>
      <ProfileHeader nikename={props.nikename} level={props.level}/>
      <ul>
        <li>设置1</li>
        <li>设置2</li>
        <li>设置3</li>
        <li>设置4</li>
      </ul>
    </div>
  )
}

ProfileHeader.js 是profile.js 的子文件 (注意是函数组件)

import React from "react";

export default function ProfileHeader(props) {
  console.log(props,"ProfileHeaderProfileHeaderProfileHeader");
  return (
    <div>
      <h2>用户昵称: {props.nikename}</h2>
      <h2>用户等級: {props.level}</h2>
    </div>
  );
}

实际截图

image.png

** 以上可以实现但是非父子组件就搞不定了 **

补充以上缺陷使用属性展开 {...props},就可以省略Profile.js中的那段多余的传值

image.png

2. 跨组件通讯Context应用场景

Context相关API

(1) React.createContext
 --创建一个需要共享的Context对象:
-- 如果一个组件订阅了Context,那么这个组件会从离自身最近的那个匹配的 Provider 中读取到当前的context值;
 -- defaultValue是组件在顶层查找过程中没有找到对应的Provider,那么就使用默认值
const myContext = React.create


(2) Context.Provider
-- 每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化:
-- Provider 接收一个 value 属性,传递给消费组件;
-- 一个 Provider 可以和多个消费组件有对应关系;
-- 多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据;
-- 当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染;
<MyContext.Provider value={/*某个值*/}>

(3) Class.contextType
-- 挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象:
-- 这能让你使用 this.context 来消费最近 Context 上的那个值; p 你可以在任何生命周期中访问到它,包括 render 函数中;
MyClass.contextType = MyContext

(4) Context.Consumer
-- 这里,React 组件也可以订阅到 context 变更。这能让你在 函数式组件 中完成订阅 context。 
-- 这里需要 函数作为子元素(function as child)这种做法; 
-- 这个函数接收当前的 context 值,返回一个 React 节点;
<MyContext.Consumer>
  {value => /*基于context值进行渲染*/}
</MyContext.Consumer>

(4.1) Class 类组件的具体使用代码如下:

import React, { Component } from "react";

// 1.创建Context对象
// defaultValue是组件在顶层查找过程中没有找到对应的Provider,那么就使用默认值
// const UserContext = React.createContext(defaultValue)
export const UserContext = React.createContext({
  nikename: "aaaaa",
  level: -100,
});


// 组件
// 3. 具体的使用方式,记住不能使用函数组件
class ProfileHeader extends Component {
  render() {
    console.log(this.context);
    return (
      <div>
        <h2>用户昵称: {this.context.nikename}</h2>
        <h2>用户等級: {this.context.level}</h2>
      </div>
    );
  }
}
// 4. 把创建的Context对象赋值给ProfileHeader的contextType就可以在孙子组件中拿到从爷爷组件传递的数据了
ProfileHeader.contextType = UserContext;

function Profile(props) {
  return (
    <div>
      <ProfileHeader />
      <ul>
        <li>设置1</li>
        <li>设置2</li>
        <li>设置3</li>
        <li>设置4</li>
      </ul>
    </div>
  )
}


export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      objName: {
        nikename: "coderhzc",
        level: 88,
      },
    };
  }
  render() {
    return (
      <div>
        {/* 2.具体使用 */}
        {/* 
           (1) Provider 接收一个 value 属性,传递给消费组件;
           (2) 当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染;
         */}
        <UserContext.Provider value={this.state.objName}>
          <Profile />
        </UserContext.Provider>
      </div>
    );
  }
}

实际截图

image.png

### (4.2) 函数组件的具体使用代码如下:

import React, { Component } from "react";

// 1.创建Context对象
// defaultValue是组件在顶层查找过程中没有找到对应的Provider,那么就使用默认值
// const UserContext = React.createContext(defaultValue)
const UserContext = React.createContext({
  nikename: "aaaaa",
  level: -100,
});

// 组件
// 3. 函数组件的具体使用
function ProfileHeader() {
  return (
    <div>
      <UserContext.Consumer>
        {
         value => {
          console.log(value);
          return (
            <div>
              <h2>用户昵称: {value.nikename}</h2>
              <h2>用户等級: {value.level}</h2>
            </div>
          );
        }
        }
      </UserContext.Consumer>
    </div>
  );
}

function Profile(props) {
  return (
    <div>
      <ProfileHeader />
      <ul>
        <li>设置1</li>
        <li>设置2</li>
        <li>设置3</li>
        <li>设置4</li>
      </ul>
    </div>
  );
}

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      objName: {
        nikename: "coderhzc11",
        level: 88,
      },
    };
  }
  render() {
    return (
      <div>
        {/* 2.具体使用 */}
        {/* 
           (1) Provider 接收一个 value 属性,传递给消费组件;
           (2) 当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染;
         */}
        <UserContext.Provider value={this.state.objName}>
          <Profile />
        </UserContext.Provider>
      </div>
    );
  }
}

实际截图

image.png

5. 多个Context使用代码如下(不推荐做):

import React, { Component } from 'react';

// 创建Context对象
const UserContext = React.createContext({
  nickname: "aaaa",
  level: -1
})

const ThemeContext = React.createContext({
  color: "black"
})

function ProfileHeader() {
  // jsx -> 嵌套的方式
  return (
    <UserContext.Consumer>
      {
        value => {
          return (
            <ThemeContext.Consumer>
              {
                theme => {
                  return (
                    <div>
                      <h2 style={{color: theme.color}}>用户昵称: {value.nickname}</h2>
                      <h2>用户等级: {value.level}</h2>
                      <h2>颜色: {theme.color}</h2>
                    </div>
                  )
                }
              }
            </ThemeContext.Consumer>
          )
        }
      }
    </UserContext.Consumer>
  )
}

function Profile(props) {
  return (
    <div>
      <ProfileHeader />
      <ul>
        <li>设置1</li>
        <li>设置2</li>
        <li>设置3</li>
        <li>设置4</li>
      </ul>
    </div>
  )
}

export default class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      nickname: "kobe",
      level: 99
    }
  }

  render() {
    return (
      <div>
        <UserContext.Provider value={this.state}>
          <ThemeContext.Provider value={{ color: "red" }}>
            <Profile />
          </ThemeContext.Provider>
        </UserContext.Provider>
      </div>
    )
  }
}

实际截图

image.png

终极写法:组件抽离的写法

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容