React中引用的正确原型是什么?


84

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

存储的ref如下所示:

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

此引用的正确propType是什么?


8
由于ref不可序列化,因此将它们放入Redux存储区不是一个好主意。尽管如此,传递给refprop的值是一个函数,第一个参数是对DOM元素的引用或为null。这是一个功能
rishat

5
您不能使用propType refs,但你可以使用它props。由于您将其传递给redux存储,因此将其表示为proplike this.props.myRefToBePutInReduxGlobalStoremyRefToBePutInReduxGlobalStore应该是节点的类型,所以PropTypes.node应该为您工作
原因

我认为应该是PropType.object因为ref基本上是对象的类实例。因此,当您将ref元素作为道具传递时,它将是对象类型
Hriday Modi

Answers:


96

TL; DR

如果您想要输入仅需要本机DOM元素(例如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从redux传递mapStateToProps。DOM元素的道具类型为:(myRefToBePutInReduxGlobalStore: PropTypes.instanceOf(Element)如果它是DOM元素)。虽然,我会:

  1. 将其重命名为myElementToBePutInReduxGlobalStore(元素不是引用)
  2. 避免在Redux存储中存储不可序列化的数据
  3. 避免按照React工程师Seb Markbage的解释在道具中传递元素

对实际问题的长答案

问:React中引用的正确原型是什么?

用例示例:

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示例中的一个)

注意:从历史上看,您也可以使用字符串ref,但它被认为是旧版,因此会从react中删除

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

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

很多好的答案

ref 可以指向DOM元素以外的其他内容。

如果要完全灵活:

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

上面只是强制了带有current属性的对象ref的形状。对于任何类型的参考,它都将始终工作。出于使用prop类型的目的(这是在开发时发现任何不一致之处的一种方式),这可能就足够了。这似乎不太可能与形状的物体{ current: [any] },并传递到一个refToForward道具,会不会是一个实际的参考。

但是,您可能希望声明您的组件不希望任何类型的引用,而只是希望某种类型,只要它需要该引用即可。

我已经设置了一个沙箱,展示了几种声明ref的不同方法,甚至包括一些非常规的方法,然后使用多种prop类型对其进行测试。你可以在这里找到它


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

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

如果只希望引用指向React类组件:

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

如果只希望引用指向功能组件的refuseImperativeHandle公开一些公共方法:

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

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


没有一种好的方法可以为引用声明prop类型,这取决于用法。如果您的参考指向非常明确的东西,那么值得添加特定的道具类型。否则,仅检查一般形状就足够了。


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

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

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

以下React Docs页面提供了有关如何使用ref的更多见解,包括对象和回调,以及如何使用useRef钩子

感谢@Rahul Sagore,@ Ferenk Kamra,@ svnm和@Kamuela Franco来更新答案


2
它给出了Element未定义在服务器端的渲染。有什么解决办法吗?
Rahul Sagore

好点子。那么这个垫片呢?Element = typeof Element === 'undefined' ? function(){} : Element(由Ryan Florence建议在github问题中提出)。如果它适合您,我可以将其添加到我的答案中。
Pandaiolo

我想通了,并添加了这个if (!isBrowser) { global.Element = null; }。为我工作。isBrowser = typeof window !== 'undefined';
Rahul Sagore'1

好答案。我希望TL; DR成为响应的重中之重。
Kamuela Franco

12

与@Pandaiolo的帖子非常相似,

PropTypes.elementType 现在已添加

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

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


感谢@svnm,我已经更新了我的答案以反映这一点,这使它更简单!
Pandaiolo

1
最后,这elementType对我不起作用,因此我实际上在沙箱中针对可被ref指向的不同类型的组件测试了一堆prop类型。结果如下:codesandbox.io/s/loving-benz-w6fbh。我不确定我是否涵盖了所有可能性,但似乎DOM元素的正确原型是instanceOf(Element)(或object),对于类来说是instanceOf(Component)(或object),对于使用useImperativeHandle它的功能组件的特定用例是object。有什么想法吗?
Pandaiolo


1

我检查了上述所有答案,但从反应中得到了警告,因此我进行了很多研究,得出了正确的答案。

import React, { Component } from 'react';

ComponentName.propTypes = {
  reference: PropTypes.oneOfType([
    PropTypes.func,
    PropTypes.shape({ current: PropTypes.instanceOf(Component) }),
  ]),
};
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.