关于javascript:react之组件通信

前言

      最新在做react的B端我的项目、因为我的项目中没有用到Redux等数据管理库、所以波及到了很多组件之前的数据传递和嵌套组件如何传递的形式,温故而知新 特此整顿记录一下。

常见的组建通信的形式:

  • 父子组件通信
  • 子父组件通信
  • 兄弟组件通信
  • 爷孙通信(嵌套组件)
  • 等等

代码环境:

react: ^16.13.0

react-dom:^16.8.2

父子组件通信:

通常来说是父组件通过props、refs等形式来调用子组件的办法和属性等;

props: 子组件承受父组件的值进行视图更新

class 组件:

import React, { Component } from 'react'

// 子组件
class Child extends Component {
  constructor(props) {
    super(props)
    this.state = {}
  }

  render() {
    const { mun } = this.props;
    return (
      <>
        这里是child子组件:
        <p>{ mun }</p>
      </>
    )
  }
}

// 父组件
class Parent extends Component {
  constructor(props) {
    super(props)
    this.state = {
      mun:1
    }
  }

  handleParent = () => {
    this.setState({
      mun: this.state.mun + 1
    })
  }

  render() {
    const { mun } = this.state
    return (
      <>
        <button onClick={this.handleParent}>我是父组件的按钮。你能够点击我</button>
        <br />

        <Child mun={mun} />
      </>
    )
  }
}

export default Parent

Hooks组件:

import React, { useState } from 'react'
const Child = (props) => {

  const { mun } = props;
  return (
    <>
      这里是child子组件:
      <p>{ mun }</p>
    </>
  )
}


const Parent = () =>{
  const [mun, setMun] = useState(0)

  const handleParent = () => {
    setMun((value) => {
      return value + 1
    })
  }

  return (
    <>
      <button onClick={handleParent}>我是父组件的按钮。你能够点击我</button>
      <br />

      <Child mun={mun} />
    </>
  )
}

export default Parent

refs:父组件通过申明ref拿到子组件的对象、进行操作子组件的对象办法

class 组件:

import React, { Component, createRef } from 'react'

// 子组件
class Child extends Component {
  constructor(props) {
    super(props)
    this.state = {
      mun:1
    }
  }

  // 子组件累加累加
  accumulation = () => {
    this.setState({
      mun: this.state.mun + 1
    })
  } 

  render() {
    const { mun } = this.state
    return (
      <>
        这里是child子组件:
        <p>{ mun }</p>
      </>
    )
  }
}


// 父组件
class Parent extends Component {
  constructor(props) {
    super(props)

    // 通过ref管制
    this.createRef = createRef()
    this.state = {}
  }

  handleParent = () => {
    this.createRef && this.createRef.current.accumulation()
  }

  render() {
    return (
      <>
        <button onClick={this.handleParent}>我是父组件的按钮。你能够点击我</button>
        <br />

        <Child ref={this.createRef} />
      </>
    )
  }
}

export default Parent

Hooks 组件:

留神:在hooks中须要通过forwardRef转发获取ref的值,而后通过useImperativeHandle向父组件抛出子组件的办法。

import React, { useRef, useState, useImperativeHandle, forwardRef } from 'react'

const Child = forwardRef((_, ref) => {

  const [mun, setMun] = useState(0)

  // 累加办法
  const accumulation = () => {
    setMun((value) => {
      return value + 1
    })
  }
  
  // 给父组件抛出办法
  useImperativeHandle(ref, () => ({
    accumulation,
  }), [accumulation]);

  return (
    <>
      这里是child子组件:
      <p>{ mun }</p>
    </>
  )
})

const Parent = () =>{
  const ChildRef = useRef(null);

  const handleParent = () => {
    ChildRef.current && ChildRef.current.accumulation()
  }

  return (
    <>
      <button onClick={handleParent}>我是父组件的按钮。你能够点击我</button>
      <br />

      <Child ref={ChildRef} />
    </>
  )
}

export default Parent

子父组件通信:

子组件通过CallBack回调函数的形式来拿到父组件的办法或者属性等

Class 组件:

import React, { Component, createRef } from 'react'

// 子组件
class Child extends Component {
  constructor(props) {
    super(props)
    this.state = {
      mun:0
    }
  }

  // 子组件累加累加
  accumulation = () => {
    const { handleParent } = this.props
    const { mun } = this.state

    this.setState({
      mun:this.state.mun + 1
    },() => {
      handleParent(this.state.mun)
    })
  } 

  render() {
    const  { mun } = this.props
    return (
      <>
        这里是child子组件:
        {/* <p>{ mun }</p> */}
        <button onClick={this.accumulation}>我是子组件的按钮、能够点击我</button>
      </>
    )
  }
}


// 父组件
class Parent extends Component {
  constructor(props) {
    super(props)

    // 通过ref管制
    this.ChildRef = createRef()
    this.state = {
      getChildmun:0
    }
  }

  handleParent = (_mun) => {
    this.setState({
      getChildmun:_mun
    })
  }

  render() {
    const { getChildmun } = this.state
    return (
      <>
        <h2>我是父组件</h2>
        <p>子组件管制的值:{ getChildmun }</p>
        <br />
        <Child handleParent={this.handleParent} />
      </>
    )
  }
}

export default Parent

Hooks 组件:

import React, { useState, useEffect } from 'react'

const Child = (props) => {
  const { handleParent } = props;
  const [mun,setMun] = useState(0)

   // 子组件累加累加
  const accumulation = () => {
    setMun((value) => {
      return value + 1
    })
  } 

  useEffect(() => {
    if(mun !== 0) {
      handleParent(mun)
    }
  }, [mun]);

  return (
    <>
      这里是child子组件:
      <button onClick={accumulation}>我是子组件的按钮、能够点击我</button>
    </>
  )
}



const Parent = () =>{
  const [getChildmun,setChildmun] = useState(0);

  return (
    <>
        <h2>我是父组件</h2>
        <p>子组件管制的值:{ getChildmun }</p>
        <br />
        <Child handleParent={(mun) => setChildmun(mun)} />
    </>
  )
}

export default Parent

兄弟组件通信:

兄弟组件通信个别都是在一个父组件下平级的两个兄弟组件、利用父组件当中介进行传递

Class 组件:

import React, { Component, createRef } from 'react'

// 子组件1
class Child1 extends Component {
  constructor(props) {
    super(props)
    this.state = {
      mun:0
    }
  }

  render() {
    const { brother } = this.props

    return (
      <>
        <h2>我是Child1组件:{brother}</h2>
      </>
    )
  }
}

// 子组件1
class Child2 extends Component {
  constructor(props) {
    super(props)
    this.state = {
      mun:0
    }
  }

  // 扭转本人的值、通过父组件传递
  accumulation = () => {
  const { brotherCallback } = this.props
    
   this.setState({
    mun:this.state.mun + 1
   }, () => {
    brotherCallback(this.state.mun)
   })
  } 

  render() {
    const  { mun } = this.props
    return (
      <>
        <h2>我是Child2组件:</h2>
        <button onClick={ this.accumulation }>点击我 扭转[Child1]组件的值</button>
      </>
    )
  }
}

// 父组件
class Parent extends Component {
  constructor(props) {
    super(props)

    // 通过ref管制
    this.ChildRef = createRef()
    this.state = {
      brother:0
    }
  }

  // 利用中介的形式
  brotherCallback = (mun) => {
    this.setState({
      brother:mun
    })
  }

  render() {
    const { brother } = this.state 
    return (
      <>
        <h2>我是父组件</h2>
        <hr />
        <Child1 brother={brother} />
        <hr />
        <Child2 brotherCallback={this.brotherCallback}/>
      </>
    )
  }
}

export default Parent

Hooks 组件:

import React, { useState,useEffect } from 'react'

const Child1 = (props) => {
  const { brother } = props;
  return (
    <>
       <h2>我是Child1组件:{brother}</h2>
    </>
  )
}

const Child2 = (props) => {
  const [mun, setMun] = useState(0)
  const { brotherCallback } = props

  // 扭转本人的值、通过父组件传递
  const accumulation = () => {
    setMun((value) => {
      return value + 1
    })
  } 

  useEffect(() => {
   if(mun !== 0 ) {
    brotherCallback(mun)
   }
  }, [mun])

  return (
    <>
      <h2>我是Child2组件:</h2>
      <button onClick={accumulation }>点击我 扭转[Child1]组件的值</button>
    </>
  )
}

const Parent = () => {
  const [brother,setBrother] = useState(0);
  return (
    <>
       <h2>我是父组件</h2>
        <hr />
        <Child1 brother={brother} />
        <hr />
        <Child2 brotherCallback={(mun) => setBrother(mun)}/>
    </>
  )
}

export default Parent

(爷孙组件)嵌套组件:

嵌套组件其实也能够采纳父子组件的传递形式、然而如果层级过深显然不好保护,所以这里举荐采纳Context进行保护数据源的状态

详情请看:Context文档形容的很具体。

Class 组件:

import React, { Component, createRef } from 'react'

// 前期能够把他独自放在一个js文件维护
const ThemeContext = React.createContext();

// 孙子组件
class Grandson extends Component{
  constructor(props) {
    super(props)
    this.state = {}
  }

  static contextType = ThemeContext;
  
  shouting = () => {
    const { grandsonCallback } = this.context
    grandsonCallback({
      massge:"我累了、覆灭吧"
    })
  }

  render() {
    const { parentObj } = this.context
    return (
      <>
       <h2>我是孙子组件</h2>
       <p>接管的值:{parentObj.name} 年龄{parentObj.age}岁</p>
       <button onClick={this.shouting}>隔空喊话</button>
      </>
    )
  }
}

// 儿子组件
class Child extends Component {
  constructor(props) {
    super(props)
    this.state = {}
  }

  render() {
    return (
      <>
       <h2>我是儿子组件</h2>
       <hr />
       <Grandson />
      </>
    )
  }
}

// 父组件
class Parent extends Component {
  constructor(props) {
    super(props)

    this.state = {
      parentObj:{
        name:"我是你爷爷",
        age:88
      },
      // 承受孙子组件的数据
      grandson:{}
    }
  }

  grandsonCallback = (data) => {
    this.setState({
      grandson:data
    })
  }
  render() {
    const { parentObj, grandson } = this.state;
    return (
      <>
        <h2>我是父组件</h2>
        <p>{( grandson && grandson.massge ) ? grandson.massge : '' }</p>
        <hr />
        <ThemeContext.Provider value={ { parentObj, grandsonCallback: this.grandsonCallback } }>
          <Child />
        </ThemeContext.Provider>
      </>
    )
  }
}

export default Parent

Hooks 组件:

import React, { useState, useContext } from 'react'

// 前期能够把他独自放在一个js文件维护
const ThemeContext = React.createContext();

const Grandson = () => {
  const context = useContext(ThemeContext)
  const { parentObj, grandsonCallback } = context;

  const shouting = () => {
    grandsonCallback({
      massge:"我累了、覆灭吧"
    })
  }

  return (
    <>
     <h2>我是孙子组件</h2>
     <p>接管的值:{parentObj.name} 年龄{parentObj.age}岁</p>
     <button onClick={shouting}>隔空喊话</button>
    </>
  )
}

const Child = () => {
  return (
    <>
      <h2>我是儿子组件</h2>
      <hr />
      <Grandson />
    </>
  )
}

const Parent = () =>{
  const [grandson, setGrandson] = useState({});
  const [parentObj, setParentObj] = useState(
  {
    name:"我是你爷爷",
    age:88
  });

  const grandsonCallback = (data) => {
    setGrandson(data)
  }

  return (
    <>
      <h2>我是父组件</h2>
      <p>{( grandson && grandson.massge ) ? grandson.massge : '' }</p>
      <hr />
      <ThemeContext.Provider value={ { parentObj, grandsonCallback } }>
        <Child />
      </ThemeContext.Provider>
    </>
  )
}

export default Parent

最初

     其实在常见的组件通信中,以上的形式入不敷出、然而面对简单的大型项目中还是举荐采纳redux这样的状态存储对象来对立治理、如果redux灵活性不高,这里也举荐采纳dva进行治理、就像它的个性一样:疾速上手、易学易用。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理