React父组件调用子组件中的方法实例详解

  本文主要讲述ref 的应用仅为父组件调用子组件场景下的应用方式1

  Class组件

  1. 自定义事件

   Parent.js

  import React, { Component } from 'react';
  import Child from './Child';
  class Parent extends Component {
  componentDidMount () {
  console.log(this.childRef)
  }
  handleChildEvent = (ref) => {
  // 将子组件的实例存到 this.childRef 中, 这样整个父组件就能拿到
  this.childRef = ref
  }
  //按钮事件处理
  handleClick = () => {
  // 通过子组件的实例调用组组件中的方法
  this.childRef.sendMessage()
  }
  render () {
  return (
  <>
  <Child
  onChildEvent={this.handleChildEvent}
  />
  <button onClick={this.handleClick}>Trigger Child Event</button>
  </>
  );
  }
  }
  export default Parent;

  Child.js

  import React, { Component } from 'react';
  class Child extends Component {
  //子组件完成挂载时, 将子组件的方法 this 作为参数传到父组件的函数中
  componentDidMount () {
  // 在子组件中调用父组件的方法,并把当前的实例传进去
  this.props.onChildEvent(this)
  }
  // 子组件的方法, 在父组件中触发
  sendMessage = () => {
  console.log('sending message')
  }
  render () {
  return ( <div>Child</div> );
  }
  }
  export default Child;
  2. 使用 React.createRef()

  ParentCmp.js

  import React, { Component } from 'react';
  import ChildCmp from './ChildCmp';
  export default class ParentCmp extends Component {
  constructor(props) {
  super(props)
  // 创建Ref
  this.childRef = React.createRef()
  }
  // 按钮事件
  handleClick = () => {
  // 直接通过 this.childRef.current 拿到子组件实例
  this.childRef.current.sendMessage()
  }
  render () {
  return (
  <>
  <ChildCmp ref={this.childRef} />
  <button onClick={this.handleClick}>Trigger Child Event</button>
  </>
  );
  }
  }

  而子组件就是一个普通的组件

  ChildCmp.js

  import React, { Component } from 'react';
  export default class ChildCmp extends Component {
  sendMessage = () => {
  console.log('sending message')
  }
  render () {
  return 'Child';
  }
  }

  3. 使用回调Refs

  回调 Refs 是另一种设置 Ref 的方式,可以控制 refs 被设置和解除的时间。

  此时,需要传递一个函数,不同于传递 createRef() 创建的 ref 属性。

   current也不是访问 Ref 必需。

  ParentCmp.js

  import React, { Component } from 'react';
  import ChildCmp from './ChildCmp';
  export default class ParentCmp extends Component {
  constructor(props) {
  super(props)
  // 创建 Ref,不通过 React.createRef()
  this.childRef = null
  }
  // 设置 Ref
  setChildRef = (ref) => {
  this.childRef = ref
  }
  // 按钮事件
  handleClick = () => {
  // 直接通过 this.childRef 拿到子组件实例
  this.childRef.sendMessage(`Trigger Child Event from Parent`)
  }
  render () {
  return (
  <>
  <ChildCmp ref={this.setChildRef} />
  <button onClick={this.handleClick}>Trigger Child Event</button>
  </>
  );
  }
  }

  而子组件还是一个普通的组件

  ChildCmp.js

  import { Component } from 'react';
  export default class ChildCmp extends Component {
  sendMessage = (message) => {
  console.log('sending message:', message)
  }
  render () {
  return 'Child';
  }
  }

  【注】对比自定义事件方式,回调 Refs 更像是精简的自定义事件方式:

  在自定义事件名称变成了 ref之后,子组件内无需手动绑定。

  Function组件

  在普通默认情况下,无法在函数组件上使用 ref 属性,主要是没有实例。上述两种方式都行不通。

  解决办法就是使用 forwardRef 和 useImperativeHandle。

  不过在函数的内部是可以使用 useRef 钩子来获取组件内的 DOM 元素。

  Parent.js

  import React, { useRef } from 'react';
  import Child from './Child';
  const Parent = () => {
  // 通过 Hooks 创建 Ref
  const childRef = useRef(null)
  const handleClick = () => {
  childRef.current.sendMessage()
  }
  return (
  <>
  <Child
  ref={childRef}
  />
  <button onClick={handleClick}>Trigger Child Event</button>
  </>
  );
  }
  export default Parent;

  Child.js

  import React, { forwardRef, useImperativeHandle } from 'react';
  const Child = forwardRef((props, ref) => {
  //将子组件的方法 暴露给父组件
  useImperativeHandle(ref, () => ({
  sendMessage
  }))
  const sendMessage = () => {
  console.log('sending message')
  }
  return ( <div>Child</div> );
  })
  export default Child;

  注:

  上面的例子中只是简单地演示了父子组件之间的方法调用,当然实际情况中子组件中可以也会有自己的 ref 指向自己内部的 DOM 元素,不过这些原理都是一样的。

  补充:子组件调用父组件方法

  子组件中调用父组件的setId方法

  父组件

  <NavBarX
  item={item}
  current={current}
  getBatchDetails={(id) => this.getBatchDetails(0, id)}
  setId={(id, callback) => this.setState({ id }, callback)}
  onRef={this.onNavBarXRef}
  />

  子组件

  this.props.setId(prePageId, () => {
  getBatchDetails(prePageId)
  })

       上述就是全部内容,后续请大家多多关注!

原创文章,作者:网友投稿,如若转载,请注明出处:https://www.cloudads.cn/archives/4072.html

发表评论

登录后才能评论