react hook组件间通讯的4种方式

前言

自从react官方引入了hook,很多小伙伴都从老的class组件换为hook组件,但因为hook组件的传参和class组件传参还是有些区别的,所以下文汇总了4种传参方式

一、父传子

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

1、父组件
import React, { useState } from 'react'

import ChildrenCom from './child'

// 父组件
const ParentCom = () => {
  const [name] = useState('A.Liang')

  return (
    <div>
      <h2>父组件</h2>
      <ChildrenCom name={name} />
    </div>
  )
}

export default ParentCom
2、子组件
import React, { useState } from 'react'

import ChildrenCom from './child'

// 父组件
import React, { useEffect } from 'react'

// 子组件
const ChildrenCom = props => {
  const { name } = props

  useEffect(() => {
    console.log('props==>', props)
  })

  return (
    <div>
      <h4>子组件: </h4>
      <p>父传给子组件的name: {name}</p>
    </div>
  )
}

export default ChildrenCom

二、子传父

父组件props传递回调函数给子组件

如果子组件想向父组件传递某些值,或者是子组件在执行某一段逻辑后想执行父组件中的某一段逻辑,此时可以在父组件中写好对应的逻辑函数,通过props传递这个函数给子组件进行调用即可

1、父组件
import React, { useState } from 'react'

import Child from './child'
// 父组件
const ParentCom = () => {
  const [count, setCount] = useState(0)

  // 获取子组件传过来的value值并设置到count,val参数就是子组件的value值
  const getChildrenValue = val => {
    setCount(val)
  }

  return (
    <div>
      <h2>父组件</h2>
      <p>获取子组件传过来的值:{count}</p>
      {/* 这里是重要代码,向子组件传递getValue这个prop,它的值是一个回调函数 */}
      <Child getValue={getChildrenValue} />
    </div>
  )
}

export default ParentCom
2、子组件
import React, { useState } from 'react'

// 子组件
const ChildrenCom = props => {
  const [value, setValue] = useState(0)

  const addValue = () => {
    setValue(value + 1)
    // 向父组件传递每次递增的value值
    props.getValue(value + 1)
  }

  return (
    <div>
      <h4>子组件</h4>
      <button onClick={addValue}>点击改变子组件的value值:{value}</button>
    </div>
  )
}

export default ChildrenCom

三、父传后代

使用useContext 实现跨组件传值

const value = useContext(MyContext);

useContext接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定。

1、context.js
import { createContext } from 'react'

const myContext = createContext(null)

export default myContext
2、父组件
import React, { useReducer } from 'react'

import myContext from './createContext'
import Child from './child'

const reducer = (state, action) => {
  const [type, payload] = action
  switch (type) {
    case 'set':
      return {
        ...state,
        ...payload,
      }
    default:
      return {
        ...state,
        ...payload,
      }
  }
}

const initData = {
  name: 'A.Liang',
}

const ParentCom = () => {
  const [state, dispatch] = useReducer(reducer, initData)

  return (
    <div style={{ backgroundColor: '#f2f2f2' }}>
      <h1>Test最顶层组件----实现跨组件间传值。</h1>
      <button
        onClick={() => {
          dispatch(['set', { name: '父组件改变了名字' }])
        }}
      >
        点我修改name
      </button>
      <br />
      父组件-name:{state.name}
      <hr />
      <myContext.Provider
        value={{
          name: state.name,
          // 把最顶层Test组件的dispatch传递下去给后代组件,这样后代组件就都能修改最顶层组件的数据了。
          proDispatch: dispatch,
        }}
      >
        {/* 子组件 */}
        <Child />
      </myContext.Provider>
    </div>
  )
}

export default ParentCom
3、子组件
import React, { useContext } from 'react'

import myContext from './createContext'
import ChildChild from './child-child'

// 子组件
const ChildrenCom = () => {
  const { name, proDispatch } = useContext(myContext)

  function changeName() {
    proDispatch([
      'set',
      {
        name: '子组件修改了名字',
      },
    ])
  }

  return (
    <div>
      <h4>子组件: </h4>
      <button onClick={changeName}>子组件修改父组件的name</button>
      <p>父传给子组件的name: {name}</p>
      <ChildChild />
      <hr />
    </div>
  )
}

export default ChildrenCom
4、子孙组件
import React, { useContext } from 'react'

import myContext from './createContext'

// 子孙组件
const ChildrenCom = () => {
  const { name, proDispatch } = useContext(myContext)

  function changeName() {
    proDispatch([
      'set',
      {
        name: '子孙组件修改了名字',
      },
    ])
  }

  return (
    <div>
      <h4>子孙组件: </h4>
      <button onClick={changeName}>子孙组件修改父组件的name</button>
      <p>父传给子孙组件的name: {name}</p>
      <hr />
    </div>
  )
}

export default ChildrenCom

四、父调用子的函数

如果想在父组件中调用子组件的某个函数,或者是使用子组件的某个值,可以使用这个方式(尽量少用)

react官网的一段文字描述:
useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref 这样的命令式代码。useImperativeHandle 应当与 forwardRef 一起使用

1、父组件
import React, { useRef } from 'react'

import ChildrenCom from './child'

// 父组件
const ParentCom = () => {
  // 获取子组件实例
  const childRef = useRef()

  // 调用子组件的onChange方法
  const onClickChange = () => {
    childRef.current.onChange()
  }

  return (
    <div>
      <h2>父组件</h2>
      <button onClick={onClickChange}>点击调用子组件onChange函数</button>
      <ChildrenCom ref={childRef} demonName="demo1" />
    </div>
  )
}

export default ParentCom
2、子组件
import React, {
  useState,
  useEffect,
  useImperativeHandle,
  forwardRef,
} from 'react'

// 子组件
const ChildrenCom = forwardRef((props, ref) => {
  const [value, setValue] = useState(0)
  const [name, setName] = useState('A.Liang')
  const { demonName } = props

  useEffect(() => {
    console.log('ref==>', ref)
  })

  // 自定义暴露给父组件的实例值 (useImperativeHandle 要配合 forwardRef使用)
  useImperativeHandle(ref, () => ({
    // 暴露函数给父组件调用
    onChange,
    // 也可以暴露子组件的状态值给父组件使用
  }))

  const onChange = () => {
    setValue(value + 1)
    setName(name === 'A.Liang' ? 'simon' : 'A.Liang')
  }

  return (
    <div>
      <h4>子组件: {demonName}</h4>
      <p>子组件的value: {value}</p>
      <p>子组件的name: {name}</p>
      <button onClick={onChange}>点击改变value和name</button>
    </div>
  )
})

export default ChildrenCom

代码下载(*p-hook**分支):https://gitee.com/staraliang/react17-app/tree/p-hook/

觉得本文写的不错的,希望点赞、收藏、加关注,每月不定期更新干货哦,谢谢您嘞!

你可能感兴趣的文章:

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员良仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值