React Hook中父组件调用子组件的方法


字数:1.3k 阅读时长:5分钟 阅读:85

React Hook 是函数式组件开发模式,没有组件的实例,没有 this 指向,因此无法使用组件的实例,去调用组件中的方法,这与 Vue 中的 Hook 组件有很大的不用。不过官方也提供了对应的 Hook 函数解决这类问题,本文就讲讲如何使用 forwardRefuseImperativeHandle 来实现父组件调用子组件中的方法。

React Hook父调子

一、使用场景

使用 React Hook + antd 开发页面经常遇到这样的情况,一个列表的数据有新增,编辑(更新)和删除等操作。新增和编辑通常都是弹窗中提交 form 表单数据。新增时 form 表单中默认为空,编辑时回显旧数据。
所以这就涉及到了父子组件通信问题,需要在父组件中控制子组件弹窗的展示隐藏,编辑的时候还需要传入回显的数据。
单纯的使用 props 传参可以实现,但是需要大量的使用 useEffect 来监听数据的变化,进行对应的响应式操作。这种形式显然不够直接,不够友好。
需求:在父组件直接调用子组件中的方法,来达到响应式的效果。

二、forwardRefuseImperativeHandle API

  1. forwardRef

forwardRef 是一个React API,用于在函数式组件中向子组件传递ref。通常,在函数式组件中,你不能直接访问子组件的DOM元素或实例。通过forwardRef,你可以将一个ref对象传递给子组件,从而可以在父组件中引用或操作子组件。

具体工作方式如下:

  • 通过forwardRef,你可以创建一个包装函数组件,它接受props和ref参数,并返回子组件的JSX。
  • 这个包装组件可以在渲染时将ref传递给子组件的DOM元素或子组件实例。
  • 父组件可以通过这个ref来访问或操作子组件。

示例:

1
2
3
4
const MyComponent = forwardRef((props, ref) => {
// 使用ref操作子组件或DOM元素
return <ChildComponent ref={ref} />;
});
  1. useImperativeHandle

useImperativeHandle 是一个React Hook,通常与 forwardRef 一起使用。它用于自定义将从子组件暴露给父组件的方法或属性。具体作用如下:

  • useImperativeHandle 接受两个参数,第一个参数是ref对象,第二个参数是一个回调函数。
  • 在回调函数中,你可以定义要暴露给父组件的方法或属性,并返回一个包含这些方法或属性的对象。
  • 这些方法或属性可以在父组件中通过ref对象访问。

示例:

1
2
3
4
5
6
useImperativeHandle(ref, () => ({
customMethod: () => {
// 定义要暴露给父组件的自定义方法
},
customProperty: someValue,
}));

forwardRef 和 useImperativeHandle 结合使用可以让你更好地控制父子组件之间的通信和行为。forwardRef 用于传递 ref,而 useImperativeHandle 用于定义要暴露给父组件的方法或属性。

三、父组件调用子组件的方法

  1. 创建子组件

首先,创建子组件 ChildComponent,其中使用 forwardRefuseImperativeHandle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react';
import { Modal, Form, Input, Button } from 'antd';

const ChildComponent = (props, ref) => {
const [form] = Form.useForm();
const [visible, setVisible] = useState(false);

useImperativeHandle(ref, () => ({
form,
show,
hide: () => {
form.resetFields();
setVisible(false);
},
}));

const show = (data) => {
form.resetFields(); // 重置表单字段
if (data) {
form.setFieldsValue(data); // 设置表单字段的值为旧数据
}
setVisible(true);
}

const handleOk = () => {
form
.validateFields()
.then((values) => {
// 处理表单数据
console.log('表单数据', values);
form.resetFields();
setVisible(false);
})
.catch((errorInfo) => {
console.log('表单校验失败:', errorInfo);
});
};

const handleCancel = () => {
form.resetFields();
setVisible(false);
};

return (
<Modal
open={visible}
title="编辑信息"
onOk={handleOk}
onCancel={handleCancel}
footer={[
<Button key="back" onClick={handleCancel}>
取消
</Button>,
<Button key="submit" type="primary" onClick={handleOk}>
保存
</Button>,
]}
>
<Form form={form} layout="vertical">
<Form.Item
name="name"
label="名称"
rules={[{ required: true, message: '请输入名称' }]}
>
<Input />
</Form.Item>
{/* 其他表单字段 */}
</Form>
</Modal>
);
};

export default forwardRef(ChildComponent);
  1. 在父组件中使用子组件

在父组件 ParentComponent 中,你可以通过 ref 控制子组件的显示和隐藏,并在编辑时传递旧数据给子组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React, { useRef, useState } from 'react';
import { Button } from 'antd';

const ParentComponent = () => {
const childRef = useRef(null);

const handleShowModal = (data) => {
childRef.current.show(data); // 传递旧数据给子组件
};

return (
<div>
<Button onClick={() => handleShowModal({ name: '旧数据' })}>编辑数据</Button>
<ChildComponent ref={childRef} />
</div>
);
};

export default ParentComponent;

在这个示例中,handleShowModal 函数接受一个 data 参数,该参数包含要编辑的旧数据。然后,它调用 childRef.current.show(data) 来传递旧数据给子组件。在子组件的 show 方法中,我们使用 form.setFieldsValue(data) 来设置表单字段的值为旧数据,以便在编辑时显示这些数据。


欢迎访问:天问博客

本文作者: Tiven
发布时间: 2023-08-22
最后更新: 2023-08-28
本文标题: React Hook中父组件调用子组件的方法
本文链接: https://www.tiven.cn/p/a85ce15b/
版权声明: 本作品采用 CC BY-NC-SA 4.0 许可协议进行许可。转载请注明出处!
欢迎留言,提问 ^_^
个人邮箱: tw.email@qq.com
notification icon
博客有更新,将会发送通知给您!