React 中 ref 的正确属性类型是什么?

IT技术 reactjs
2021-04-26 00:47:02

我在我的 redux 存储中存储一个 ref 并使用 mapStateToProps 为需要访问它的组件公开 ref。

存储的 ref 如下所示:

ref={node => this.myRefToBePutInReduxGlobalStore = node}

这个 ref 的正确 propType 是什么?

4个回答

TL; 博士

如果你想 prop 类型一个只需要原生 DOM 元素的 ref,例如 adiv或 an input,正确的定义如下:

refProp: PropTypes.oneOfType([
    // Either a function
    PropTypes.func, 
    // Or the instance of a DOM native element (see the note about SSR)
    PropTypes.shape({ current: PropTypes.instanceOf(Element) })
])

对原始帖子中描述的特定问题的回答

在 OP 问题的示例中,需要声明的不是 ref prop 类型,而是 ref 指向的内容,并且将从 redux 使用mapStateToProps. DOM 元素的 Prop 类型将是:(myRefToBePutInReduxGlobalStore: PropTypes.instanceOf(Element)如果它是 DOM 元素)。虽然,我会:

  1. 将其重命名为myElementToBePutInReduxGlobalStore(元素不是引用)
  2. 避免在 redux 存储中存储不可序列化的数据
  3. 正如 React 工程师 Seb Markbage 所解释的,避免在 props 中传递元素

实际问题的长答案

问:React 中 ref 的正确属性类型是什么?

示例用例:

function FancyInput({ inputRef }) {
    return (
        <div className="fancy">
            Fancy input
            <input ref={inputRef} />
        </div>
    )
}

FancyInput.propTypes = {
    inputRef: ???   // What is the correct prop type here?
}

function App(props) {
    const inputRef = React.useRef()
    useLayoutEffect(function focusWhenStuffChange() {
        inputRef.current?.focus()
    }, [props.stuff])
    return <FancyInput inputRef={inputRef} />
}

今天,react 中存在两种引用:

  1. 一个看起来像这样的对象:{ current: [something] },通常由React.createRef()助手或React.useRef()钩子创建
  2. 一个回调函数,它将[something]作为其参数接收(就像 OP 示例中的那个)

注意:从历史上看,您也可以使用字符串引用,但它被认为是遗留的,将从 react 中删除

第二项非常简单,需要以下props类型:PropTypes.func.

第一个选项不太明显,因为您可能希望指定 ref 指向的元素类型。

许多好的答案

ref 可以指向 DOM 元素以外的东西。

如果你想完全灵活:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.any })
])

以上只是强制对象 ref w/current属性的形状它始终适用于任何类型的参考。出于使用 prop 类型的目的,这是一种在开发时发现任何不一致的方法,这可能就足够了。具有 shape并传递给prop的对象似乎不太可能不是实际的 ref。{ current: [any] }refToForward

但是,您可能想声明您的组件不期望任何类型的 ref,而只期望某种类型,考虑到它需要该 ref 的用途。

我已经设置了一个沙箱,展示了几种不同的方式来声明 ref,甚至是一些非常规的方式,然后用许多 prop 类型测试它们。你可以在这里找到它


如果您只希望 ref 指向本机输入元素,而不是任何HTML Element

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.instanceOf(HTMLInputElement) })
])

如果您只希望 ref 指向 React 类组件:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.instanceOf(Component) })
])

如果您只期望一个 ref 指向一个useImperativeHandle用于公开一些公共方法的功能组件

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.object })
])

注意:上面的 prop 类型很有趣,因为它也涵盖了 react 组件和原生 DOM 元素,因为它们都继承了基础 javascript Object


没有单一的好方法可以为 ref 声明 prop 类型,这取决于用法。如果您的 ref 指向某些非常明确的内容,则值得添加特定的props类型。否则,只需检查一般形状似乎就足够了。


关于服务端渲染的注意事项

如果您的代码必须在服务器上运行,除非您已经 polyfill DOM 环境,Element否则任何其他客户端类型都将undefined在 NodeJS 中。您可以使用以下垫片来支持它:

Element = typeof Element === 'undefined' ? function(){} : Element

以下 React Docs 页面更深入地了解了如何使用 refs,包括对象和回调,以及如何使用useRef钩子

感谢@Rahul Sagore、@Ferenk Kamra、@svnm 和@Kamuela Franco 的回答更新

与@Pandaiolo 的帖子非常相似,

PropTypes.elementType 现在已添加

forwardedRef: PropTypes.oneOfType([
  PropTypes.func,
  PropTypes.shape({ current: PropTypes.elementType })
]),

如果使用 PropTypes >= 15.7.0PropTypes.elementType已于 2019 年 2 月 10 日添加到此 PR 中

我只检查首选方式,因为PropType.object不是很有value,我最终使用了这个:

PropTypes.shape({ current: PropTypes.instanceOf(Element) })

我检查了上述所有答案,但我从react中得到警告,所以我研究了很多,我得到了正确的答案。

import React, { Component } from 'react';

ComponentName.propTypes = {
  reference: PropTypes.oneOfType([
    PropTypes.func,
    PropTypes.shape({ current: PropTypes.instanceOf(Component) }),
  ]),
};