函数组件 useRef -组件设计

函数组件 useRef -组件设计

React 组件的 ref 可以帮助我们拿到组件的实例或者 DOM 对象,从而对组件内部进行修改。日常开发中,为了使得组件具有通用性,就需要减少组件之间的依赖关系。合理地使用 ref ,使得子组件只需暴露出 ref 实例方法 ,父组件无需关注子组件内部调用子组件的实例方法。

涉及到 React 相关的 API

  1. [useRef](Hook API 索引 – React (docschina.org))
  2. [forwardRef](React 顶层 API – React (reactjs.org))
  3. useImperativeHandle
  4. connect

场景:一个页面有个按钮,希望点击后出现一个弹窗,所以这个页面和弹窗组成父子组件的关系。(弹窗内部数据是由 redux 管理)

需求:弹窗组件 visible 属性交给自己管理,希望通过 useRef 暴露出一个 open() 方法,给父组件去使用,无需关注组件实现细节

子组件:弹窗组件

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
/**
* @file 弹窗组件
*/

import React, { useState, forwardRef, useImperativeHandle } from 'react'
import { Form, Modal } from 'antd'
import { connect } from 'react-redux'

function Child({ refInstance }) {
// 组件内部的 visible 属性,交由组件自己管理
const [visible, setVisible] = useState(false)

// 通过 useImperativeHandle 可以暴露出特定的实例方法
useImperativeHandle(
refInstance,
() => ({
// 暴露组件 open() 方法给父组件
open: () => {
setVisible(true)
},
}),
[]
)

return (
<Modal
title="表单预览"
visible={visible}
footer={null}
onCancel={() => setVisible(false)}
>
{
// 展示 redux 数据
redux_data
}
</Modal>
)
}

// connect 用于接收 redux 数据
const ChildrRefWrap = connect((state) => ({
redux_data: state.redux_data,
}))(Render)

// forwardRef 嵌套到最外一层
export default forwardRef((props, ref) => (
<RenderRefWrap {...props} refInstance={ref} />
))

父组件:Father

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

export default function Father() {
onst modalRef = useRef(null)

const onPreviewClick = ()=> {
// 通过 modalRef 实例暴露出 open() 方法,打开预览Modal
modalRef.current.open()
}
return (
<div>
<Button type="primary" size="small" onClick={onPreviewClick}>预览效果</Button>
</div>
)
}

参考:React 函数式组件使用 Ref - 掘金 (juejin.cn)