React 父组件如何修改子组件状态

简介

由于一个组件A中渲染的结构较多,所以我决定把组件A中使用的AntdModal组件拆分出去,成为一个组件B去负责处理自己的业务逻辑。

这时奇怪的问题增加了,我们需要通过组件A去控制组件BModal组件的显示,也就是控制Modal组件visible属性。如果把visible放在组件A的状态中,那么组件BModalonOKonCancel属性也需要通过调用组件A定义的函数才能修改visible值。

最初想法

按照上面简介中说的,我们把组件BModalvisible放在组件A中进行管理,这也就是常见的父组件给子组件传值,然后通过父组件给子组件提供的方法去修改父组件的值,那么就是这样:

import React, { Component } from 'react'
import { Card, Button, Modal, Form } from 'antd'

class A extends Component {
  state = {
    visible: false
  }

  changeModalVisible = () => {
    this.setState({
      visible: !this.state.visible
    })
  }

  render() {
    const { visible } = this.state
    return (
      <Card title='示例'>
        <B
          visible={visible}
          changeVisible={this.changeModalVisible}
        />
        <Button onClick={this.changeModalVisible}>显示Modal</Button>
      </Card>
    )
  }
}

class B extends Component {
  handleOK = () => {
    this.props.changeVisible()
    // ...
    // 省略很多代码
  }

  render() {
    const { visible, changeVisible } = this.props
    return (
      <Modal
        title='Modal'
        visible={visible}
        onOk={this.handleOK}
        onCancel={changeVisible}
      >
        <Form></Form>
      </Modal>
    )
  }
}

export default A

上面这个案例代码省略了真实项目的大部分逻辑,项目的主要逻辑就是用户触发父组件A的一个按钮点击事件,然后显示子组件BModal,提供给用户一个Form表单,用户填写数据后,点击确定的时候对表单的数据进行手动收集并提交给后端,用户点击取消就隐藏掉这个Modal

案例中的操作并没有什么不可,但实际上在我的组件A中状态和方法已经足够多了,实在是不想再往里面塞,然后我就想怎么让父组件A去修改子组件B的状态(父组件修改子组件的状态)。

使用 Refs 获得子组件

我在子组件B上添加ref属性,然后父组件A通过调用this.refs拿到子组件实例,这时就可以访问到子组件的属性和方法了。

那么,我们在子组件B中定义一个方法,这个方法实现组件对自己状态的修改操作,然后我们再在父组件A中调用这个方法就好了。

import React, { Component } from 'react'
import { Card, Button, Modal, Form } from 'antd'

class A extends Component {
  showModal = () => {
    // this.refs.XXX 拿到对应ref属性的组件
    this.refs.B.changeVisible()
  }

  render() {
    return (
      <Card title='示例'>
        <B ref='B' />
        <Button onClick={this.showModal}>显示Modal</Button>
      </Card >
    )
  }
}

class B extends Component {
  state = {
    visible: false
  }

  changeVisible = () => {
    this.setState({
      visible: !this.state.visible
    })
  }

  handleOK = () => {
    this.changeVisible()
    // ...
    // 省略很多代码
  }

  render() {
    const { visible } = this.state
    return (
      <Modal
        title='Modal'
        visible={visible}
        onOk={this.handleOK}
        onCancel={this.changeVisible}
      >
        <Form></Form>
      </Modal>
    )
  }
}

export default A

对于子组件上ref属性的使用还有一个方法,给ref传一个函数而不是字符串,这时传入这个函数的参数就是组件本身,然后我们再把这个组件赋值到父组件this的一个属性上就可以更方便的调用了,比如:

class A extends Component {
  showModal = () => {
    // this.B 就可以拿到B组件了
    this.B.changeVisible()
  }

  render() {
    return (
      <Card title='示例'>
        <B ref={B => this.B = B} />
        <Button onClick={this.showModal}>显示Modal</Button>
      </Card >
    )
  }
}

另外你还可以通过React.createRef方法去创建ref然后去绑定,比如:

class A extends Component {
  B = React.createRef()

  showModal = () => {
    // this.XXX.current 就可以拿到ref绑的组件
    this.B.current.changeVisible()
  }

  render() {
    return (
      <Card title='示例'>
        <B ref={this.B} />
        <Button onClick={this.showModal}>显示Modal</Button>
      </Card >
    )
  }
}

题外话

其实最开始我都还没想到用ref实现父组件调用子组件的方法来修改子组件的状态,然后我竟然把Modalvisible放到了redux去管理,哎,我真的是脑短路。

另外,提醒下案例中用到的命名方式(比如:A、B)只为了撰写文章方便,真实开发这样用,你会凉凉的。


版权声明:

Anand's Blog文章皆为站长Anand Zhang原创内容,转载请注明出处。

包括商业转载在内,注明下方要求的文章出处信息即可,无需联系站长授权。

请尊重他人劳动成果,用爱发电十分不易,谢谢!

请注明出处:

本文出自:Anand's Blog

本文永久链接:https://anandzhang.com/posts/frontend/12