05 组件学习3

组件通信的意义

组件之间的数据流转

组件通信

  • 父子关系——最重要
  • 兄弟关系——自定义事件模式,eventBus/通过共同的父组件通信
  • 其他关系——vue中使用vuex,react使用mobx/redux/基于hook的方案

父传子实现

实现父子通信中的父传子,把父组件中的数据传给子组件

实现步骤

  1. 父组件提供要传递的数据 - state

  2. 给子组件标签添加属性值为 state中的数据

  3. 子组件中通过 props 接收父组件中传过来的数据

    1. 类组件使用this.props获取props对象
    2. 函数式组件直接通过参数获取props对象
import React, { createRef } from "react"

// APP是父组件,
//Son1是子组件(函数组件)
//Son2是子组件(类组件)

function Son1 (props) {
  return (
    <div>
      <h2>{props.msg}</h2>
      我是函数组件
    </div>
  )
}

class Son2 extends React.Component {
  state = {
    son2Msg: this.props.msg
  }
  render () {
    return (
      <>
        <h1>{this.state.son2Msg}</h1>
        我是类组件
      </>
    )
  }
}

class App extends React.Component {
  state = {
    msg: "this is app msg"
  }
  render () {
    return (
      <div className="App">
        <Son1 msg={this.state.msg} />
        <Son2 msg={this.state.msg} />
      </div>
    )
  }
}

export default App

props说明

和vue一样,props是只读,不能做修改

props可以传递任意数据,数字,字符串,布尔值,数组,对象,函数,JSX

function Son1 (props) {
  return (
    <div>
      <h2>{props.msg}</h2>
      <h2>{props.list.map(item => <p key={item}>{item}</p>)}</h2>
      <h3>{props.userInfo.name}</h3>
      <button onClick={props.cb}>触发父组件传入的函数</button>
      {props.jsxd}
      我是函数组件
    </div>
  )
}

class App extends React.Component {
  state = {
    msg: "this is app msg",
    list: [1, 2, 3],
    userInfo: {
      name: 'seek',
      age: 18
    }
  }
  render () {
    return (
      <div className="App">
        <Son1
          msg={this.state.msg}
          list={this.state.list}
          userInfo={this.state.userInfo}
          cb={() => { console.log(123) }}
          jsxd={(<div><h1>asdfs</h1></div>)}
        />

      </div>
    )
  }
}

export default App

父传子传递函数是子传父的实现

父传子jsx类似于vue的插槽

props赋值方法

function Son1 (props) {
  const { msg, list, userInfo, db, jsxd } = props
}

function Son1 ({ msg, list, userInfo, db, jsxd }) {

}
这里写的都是原生的js函数,原生js支持的方法,react都是可以的

实际工程中会使用第二种

子传父

通过方式:父传给子一个函数,通过函数来实现子传父

import React, { createRef } from "react"

function Son1 (props) {
  const { getSonMsg } = props
  return (
    <div>
      我是函数组件
      <button onClick={() => getSonMsg(123)}>点击按钮传入父组件</button>
    </div>
  )
}

class App extends React.Component {
  state = {
    msg: "this is app msg",
    list: [1, 2, 3],
    userInfo: {
      name: 'seek',
      age: 18
    }
  }
  getSonMsg = (msg) => {
    this.setState({
      msg: msg
    })
  }
  render () {
    return (
      <div className="App">
        <h1>{this.state.msg}</h1>
        <Son1 getSonMsg={this.getSonMsg} />
      </div>
    )
  }
}

export default App

为了减少写在jsx上过多,可以将函数抽到外面

function Son12 (props) {
  const { getSonMsg } = props
  function clickHandler () {
    getSonMsg(123)
  }
  return (
    <div>
      我是函数组件
      <button onClick={clickHandler}>点击按钮传入父组件</button>
    </div>
  )
}

兄弟组件通信

在这里插入图片描述

借助共同的父组件,实现兄弟间通信

import React, { createRef } from "react"

// 目标:B组件的数据传入A
// 方案:
// 1,先把B中的数据通过子传父,传给APP
// 2,再把App接收到的Son中的数据,通过父传子,传给A、

function SonA (props) {
  return (
    <div>
      this is A
      <h2>{props.msg}</h2>
    </div>
  )
}

function SonB (props) {
  function clickHandler () {
    props.getSonMsg("我是b的msg")
  }
  return (
    <div>
      <h1>this is B</h1>
      <button onClick={clickHandler}>点击传递给组件A</button>
    </div>
  )
}

class App extends React.Component {
  state = {
    msg: "this is app msg",
  }
  getSonMsg = (msg) => {
    this.setState({
      msg: msg
    })
  }
  render () {
    return (
      <div className="App">
        <h1>APP:{this.state.msg}</h1>
        <SonA msg={this.state.msg} />
        <SonB getSonMsg={this.getSonMsg} />
      </div>
    )
  }
}

export default App

跨组件通信

了解Context机制解决

在这里插入图片描述

如上:通过APP传递给Comc,可以通过父传子,但是层数过多,很麻烦

vue中使用provide inject

react使用context

import React, { createContext, createRef } from "react"

// APP->A->B->C
// 目标:APP->C
// 1,导入createContext方法并且执行.获取provider,consumer
// 2,使用provider包裹
// 3,使用consumer包裹

const context = createContext()
const { Provider, Consumer } = context
function SonA () {
  return (
    <>
      <h3>this is SonA</h3>
      <SonB></SonB>
    </>
  )
}

function SonB () {
  return (
    <>
      <h3>this is SonB</h3>
      <SonC></SonC>
    </>
  )
}

function SonC () {
  return (
    <>
      <h3>this is SonC</h3>
      <Consumer>
        {value => <span>{value}</span>}
      </Consumer>
    </>
  )
}

class App extends React.Component {
  state = {
    msg: "this is app msg",
  }
  getSonMsg = (msg) => {
    this.setState({
      msg: msg
    })
  }
  render () {
    return (
      <Provider value={this.state.msg}>
        <div className="App">
          <SonA />
        </div>
      </Provider>
    )
  }
}

export default App

props属性

在组件内部写了,就会自动出现在children属性

children表示该组件的子节点,只要组件内部有节点,props就有该属性

children:

  • 普通文本
  • 普通标签元素
  • 函数
  • JSX

目的:高阶组件

<SonA>this is child</SonA>

如下:类似于vue的插槽

function SonA ({ children }) {
  return (
    <>
      <h3>this is SonA</h3>
      <span>{children}</span>
    </>
  )
}


class App extends React.Component {
  render () {
    return (
      <div className="App">
        <SonA><h2>this is span child</h2></SonA>
      </div>
    )
  }
}

传递函数

function SonA ({ children }) {
  children()
  return (
    <>
      <h3>this is SonA</h3>
    </>
  )
}


class App extends React.Component {
  render () {
    return (
      <div className="App">
        <SonA>{() => console.log(123)}</SonA>
      </div>
    )
  }
}

传递JSX

function SonA ({ children }) {
  return (
    <>
      <h3>this is SonA</h3>
      {children}
    </>
  )
}


class App extends React.Component {
  render () {
    return (
      <div className="App">
        <SonA>{<div><p>{'this is p'}</p></div>}</SonA>
      </div>
    )
  }
}

传递多个标签

function SonA ({ children }) {
  return (
    <>
      <h3>this is SonA</h3>
      {children.map(child => child)}
    </>
  )
}


class App extends React.Component {
  render () {
    return (
      <div className="App">
        <SonA>
          <div><p>{'this is p'}</p></div>
          <p>{'this is p'}</p>
        </SonA>
      </div>
    )
  }
}

props校验

安装属性校验包
npm install prop-types

导入prop-types包

使用组件名.propTypes={} 给组件添加校验规则

第一个会报错,因为不是数组

import React, { createContext, createRef } from "react"
// 里面有各种各样的内置校验规则
import PropTypes from 'prop-types'

const TestPropTypes = ({ list }) => {
  return (
    <>
      <div>this is test</div>
      {list.map(item => <h2 key={item}>{item}</h2>)}
    </>
  )
}

TestPropTypes.prototypes = {
  list: PropTypes.array
}


class App extends React.Component {
  state = {
    list: [1, 2, 3]
  }
  render () {
    return (
      <div className="App">
        <TestPropTypes list={2} />
        <TestPropTypes list={this.state.list} />
      </div>
    )
  }
}

export default App

四种常见结构

  1. 常见类型:array、bool、func、number、object、string

  2. React元素类型:element

  3. 必填项:isRequired

  4. 特定的结构对象:shape({})

    官方文档:

https://reactjs.org/docs/typechecking-with-proptypes.html

prop默认值

函数默认值

方法一:(调试工具能看到)

使用prop-types包,使用defaultProps定义默认值

如果父元素没有传,则使用默认值

TestPropTypes.defaultProps = {
  list: [2, 3, 4]
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3kSa0M8u-1664891769628)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20221004130305629.png)]

方法二:(调用工具看不到,但是数据是可用的),推荐方案

const TestPropTypes = ({ list = [2, 3, 7] }) => {
  return (
    <>
      <div>this is test</div>
      {list.map(item => <h2 key={item}>{item}</h2>)}
    </>
  )
}

在这里插入图片描述

类组件默认值

方案一:使用prop-types插件来实现

class TestClass extends React.Component {
  render () {
    return (
      <>
        <div>this is class component</div>
        <h2>{this.props.number}</h2>
      </>
    )
  }
}

TestClass.defaultProps = {
  number: 10
}

方法二:使用static(推荐

class TestClass extends React.Component {
  static defaultProps = {
    number: 20
  }
  render () {
    return (
      <>
        <div>this is class component</div>
        <h2>{this.props.number}</h2>
      </>
    )
  }
}

如果两个同时使用,prop-types定义为准

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值