React:将ref传递给道具的正确方法是什么?

时间:2016-08-10 04:06:16

标签: javascript reactjs

我正在尝试将组件的引用传递给另一个组件。由于risky practice我正在使用回调引用。

所以我有类似的东西:

<One ref={c => this.one = c}/>
<Two one={this.one}/>

问题在于,每当我尝试访问this.props.one内的Two时,我都会undefined

我甚至在Two上尝试了这个:

componentDidMount(){
    setTimeout(()=>{
        console.log(this.props.one);
    },5000)
}

似乎问题在于,当创建prop时,ref仍然不存在,因为它是在One安装后创建的。但我不知道如何“刷新”Two上的道具以获得已安装组件的参考。

那么将ref传递给另一个组件的正确方法是什么?

修改

有些用户建议将该逻辑封装在更高的组件中,该组件本身会呈现其他子组件。

该方法的问题在于您无法创建可重用的逻辑,并且必须在这些封装组件中反复重复相同的逻辑。

假设您要创建一个通用的<Form>组件,它将提交逻辑封装到您的商店,错误检查等。您可以执行以下操作:

<Form>
    <Input/>
    <Input/>
    <Input/>
    <Input/>
    <SubmitButton/> 
</Form>

在此示例中,<Form>无法访问子节点的实例(和方法),因为this.props.children不返回这些实例。它返回一些伪组件列表。

那么如何在不传递参考的情况下检查某个<Input/>是否检测到验证错误?

您必须使用验证逻辑将这些组件封装在另一个组件中。例如在<UserForm>中。但由于每个表单都不同,因此必须在<CategoryForm><GoupForm>等中复制相同的逻辑。这非常低效,这就是为什么我要在<Form>中封装验证逻辑并通过<Input>组件<Form>的引用。

3 个答案:

答案 0 :(得分:21)

通常,“ref”功能是React中的反模式。它的存在是为了实现副作用驱动的开发,但是为了从React的编程方式中获得最大的好处,你应尽量避免使用“refs”。

至于你的特殊问题,给一个孩子传递一个参考它的兄弟是一个鸡与蛋的情景。挂载子进程时会触发ref回调,而不是在渲染期间触发,这就是为什么示例不起作用的原因。你可以尝试的一件事是将ref推入状态,然后从状态读到另一个孩子。所以:

<One ref={c => !this.state.one && this.setState({ one: c })}/>
<Two one={this.state.one}/>

注意:如果没有!this.state.one,这将导致无限循环。

以下是此工作的codepen示例(查看控制台以查看记录的兄弟参考):http://codepen.io/anon/pen/pbqvRA

答案 1 :(得分:2)

现在使用new ref api更为简单(自React 16以来可用-感谢perilandmishap指出了这一点)。

class MyComponent extends React.Component {
  constructor (props) {
    super(props);
    this.oneRef = React.createRef();
  }

  render () {
    return (
      <React.Fragment>
        <One ref={this.oneRef} />
        <Two one={this.oneRef} />
      </React.Fragment>
    }
  }
}

您会在Two中消耗道具,例如:

this.props.one.current

此方法的一些注意事项:

该引用将是具有current属性的对象。该属性将null 直到元素/组件被安装。挂载后,它将是One的实例。装入<Two />后,应该安全地引用它。

一旦卸载了<One />实例,则引用上的current属性将恢复为null

答案 2 :(得分:1)

通常,如果您需要传递对调用时未设置的内容的引用,则可以传递lambda代替:

<One ref={c => this.one = c}/>
<Two one={() => this.one}/>

,然后将其引用为

this.props.one()

如果在调用它时已设置它,则会得到一个值。在此之前,您将获得undefined(假设尚未初始化)。

需要注意的是,当它可用时,您不一定会重新渲染,我希望它是第一个渲染器上的undefined。使用状态来保存引用确实可以解决此问题,但是您不会获得多次重新渲染。

鉴于所有这些,我建议将One中使用对Two的引用的所有代码移到呈现OneTwo的组件中,以避免所有与该策略有关的问题,以及@Carl Sverre的答案中的一个问题。