react父向子组件通信的形式

react中是以组件式进行开发,不可避免会有组件层级相互传值的情况。目前将组件通信的方法进行汇总,主要有以下几种。

一、props属 性形式进行通信

使用props形式 的通信,主要为父子组件的层级较少的情况。以弹出框dialog的 需求为例,弹出框中的外部样式是公共的,弹出框的内容需要跟进不同的业务逻辑进行显示。

// Dialog作为容器不关心内容和逻辑
// 等同于vue中slot
function Dialog(props) {
  return (
    <div style={{ border: `4px solid ${props.color || "blue"}` }}>
      {props.children}
      <div className="footer">{props.footer}</div>
    </div>
  );
}
function WelcomeDialog(props) {
  return (
    <Dialog {...props}>
      <h1>欢迎光临</h1>
      <p>感谢使用react</p>
    </Dialog>
  );
}
export default function(){
  const footer=<button onClick='()=>alert(1)'>确定</button>
  return         <WelcomeDialog color="g reen" footer={footer} /> 

}

上面弹出框的封装使用props传参,并且使用了props中children属性。

  • props中的children可以是组件(上面例子),也可以是数组、函数、对象等。为了方便操作children为数组或对象的情况.React提供了一系列函数助手,使得操作children更加方便。
  • 两个最显眼的函数助手就是 React.Children.map 以及 React.Children.forEach。它们在对应数组的情况下能起作用,除此之外,当函数、对象或者任何东西作为children传递时,它们也会起作用
    例子:封装一个radio框,在将radio的name属性和传入的value属性一致。
// 修改children
function RadioGroup(props) {
  return (
    <div>
      {React.Children.map(props.children, child => {
        //   vdom不可更改,克隆一个新的去改才行
        return React.cloneElement(child, { name: props.name });
      })}
    </div>
  );
}
// rest 除了children属性之后的其他属性,放到radio属性中
function Radio({children, ...rest}) {
  return (
    <label>
      <input type="radio" {...rest} />
      {children}
    </label>
  );
}

使用方法

<RadioGroup name="mvvm">
        <Radio value="vue">vue</Radio>
        <Radio value="react">react</Radio>
        <Radio value="react">angular</Radio>
      </RadioGroup>

props:不同层级组件形式的传递形式,父-子传递,子-父传递,兄弟传递

二、使用上下文content进行通信

context提供了无需为每层组件手动添加props,就能在组件树中进行数据传递的办法
context设计的目的是为了共享哪些对于组件树而言全局的数据。使用context可以避免使用props进行多层传递的问题。
使用context要谨慎,因为使用context,组件的复用性会比较差,如果要避免层层传递的一些属性,组件组合是一种比较好的方式

import React, { useContext } from "react";

// 1.创建上下文
const MyContext = React.createContext();
const { Provider, Consumer } = MyContext;

function Child(prop) {
  return <div>Child: {prop.foo}</div>;
}
// 使用hook消费
function Child2() {
  const context = useContext(MyContext);
  return <div>Child2: {context.foo}</div>;
}
// 使用class指定静态contextType
class Child3 extends React.Component {
    // 设置静态属性通知编译器获取上下文中数据并赋值给this.context
    static contextType = MyContext;
    render() {
        return <div>Child3: {this.context.foo}</div>
    }
}
export default function ContextTest() {
  return (
    <div>
      <Provider value={{ foo: "bar" }}>
        {/* 消费方法1:Consumer */}
        <Consumer>{value => <Child {...value} />}</Consumer>
        {/* 消费方法2:hook */}
        <Child2 />
        {/* 消费方法3:contextType */}
        <Child3 />
      </Provider>
    </div>
  );
}

1、创建Context
使用createContext可以创建上下文(context),这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。
const MyContext = React.createContext(defaultValue);
{Provider,Consumer}=MyContext
从创建的context对象中,可以解构出Provider(提供者组件-注入值)和Consumer(消费组件-获取值)
2、创建context后,在顶层使用Provider组件注入全局属性。
<Provider value={/* 某个值 */}>
获取在子组件中获取属性的3种形式。

  • 使用consumer组件
    <Consumer>{value => <Child {...value} />}</Consumer>
  • 使用hook(useContext)消费
// 使用hook消费
function Child2() {
  const context = useContext(MyContext);
  return <div>Child2: {context.foo}</div>;
}
  • 使用class指定静态contextType
class Child3 extends React.Component {
    // 设置静态属性通知编译器获取上下文中数据并赋值给this.context
    static contextType = MyContext;
    render() {
        return <div>Child3: {this.context.foo}</div>
    }
}

三、高阶组件

具体而言,高阶组件是参数为组件,返回值为新组件的函数。高阶组件 不是React的API,而是 一种组件 复用的设计模式。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。