React: 丢失 ref 值

18

我正在使用两个组件并采用以下模式: 子组件应尽可能保持隔离 - 它处理自己的验证错误。父组件应检查存在子组件之间依赖的错误。因此,在我的情况下: 密码 字段和 确认密码 字段。

这是我的代码:

a) 注册 (父组件)

设置初始状态。

 constructor() {
     super();

     this.state = {
         isPasswordMatching: false
     };
 }
render()方法中,我输出了我的子组件。通过名为callback的属性,我通过绑定父组件的this来传播isPasswordMatching()方法。目标是使该方法可以在子组件中被调用。
<TextInput
    id={'password'}
    ref={(ref) => this.password = ref}
    callback={this.isPasswordMatching.bind(this)}
    // some other unimportant props
/>

<TextInput
    id={'passwordConfirm'}
    ref={(ref) => this.passwordConfirm = ref}
    ...

isPasswordMatching() 方法检查密码是否匹配(通过引用 this.passwordthis.passwordConfirm),然后更新状态。请注意,此方法在子组件 (password 或 passwordConfirm) 中被调用。

isPasswordMatching() {
    this.setState({
        isPasswordMatching: this.password.state.value === this.passwordConfirm.state.value
    });
}

b)文本输入 (子组件)

设置初始状态。

constructor() {
    super();

    this.state = {
        value: '',
        isValid: false
    };
}

失去焦点时进行验证并更新状态。

onBlur(event) {

    // doing validation and preparing error messages

    this.setState({
        value: value,
        isValid: this.error === null
    });
}

最新消息。调用回调属性。

componentDidUpdate(prevProps) {
    if (prevProps.id === 'password' || prevProps.id === 'passwordConfirm') {
        prevProps.callback();
    }
}

问题

我的引用丢失了。场景:

  1. 渲染父组件
  2. 渲染子组件
  3. 我进入其中一个输入字段并退出(这将调用 onBlur() 方法)-状态会更新,渲染子组件
  4. componentDidUpdate() 被调用,prevProp.callback() 也被调用
  5. 当进入 isPasswordMatching() 方法时,我输出 this.passwordthis.passwordConfirm - 它们是具有预期引用值的对象。更新父组件的状态 - 组件得到渲染。
  6. 然后再次渲染所有子组件,组件得到更新,回调被调用,但这次 this.passwordthis.passwordConfirmnull

我不知道为什么引用会丢失。我应该做些什么不同的事情吗? 提前感谢。

2个回答

19
请查看 React 文档,其中有关于何时使用或不使用 refs 的重要警告和建议。
需要注意的是,当所引用的组件被卸载或者每当 ref 发生变化时,旧的 ref 将会被调用,并且传入 null 作为参数。这可以防止在存储实例的情况下出现内存泄漏,例如第二个示例中所展示的情况。此外,当像这里的示例一样使用行内函数表达式编写 refs 时,React 每次都会看到一个不同的函数对象,因此在每次更新时,ref 都会立即被调用并传入 null,然后再被调用以传入组件实例。

2
感谢您的努力。哦,原来这是我的问题。你有什么指点我该如何解决吗?我应该使用上下文吗? - be-codified
谢谢。看来这个在文档更新中丢失了。 - Paul S
2
如果您在有条件地渲染ref元素,则需要使用style={{ display: 'none' }}而不是简单地不渲染它,否则将不会创建引用。 - Raine Revere

7

我不确定这是否能回答@be-codified的问题,但我遇到了类似的问题。在我的情况下,原因是使用了一个功能组件。

https://reactjs.org/docs/refs-and-the-dom.html#refs-and-functional-components

引用和功能组件 由于函数组件没有实例,因此您不能在其上使用ref属性。 如果需要引用该组件,则应将其转换为类组件,就像在需要生命周期方法或状态时一样。
但是,只要引用DOM元素或类组件,您仍然可以在函数组件内部使用ref属性。

如果您控制要呈现的组件,则文档会解释您应该执行的操作以解决问题。

然而,在我的情况下,组件来自第三方库。因此,简单地包装组件就可以正常工作。

工作中

<div ref={element => this.elementName = element}>
    <FunctionalComponent />
</div>

未工作
将 this.elementName 设置为 null

<FunctionalComponent ref={element => this.elementName = element} />

希望这能帮助到像我一样遇到这个问题的人。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接