Javascript 将 ref 传递给 prop 的正确方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38864033/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the proper way of passing a ref to a prop?
提问by Pier
I'm trying to pass a ref of a component to another component. Since string refs are being deprecatedI'm using callback refs.
我正在尝试将一个组件的 ref 传递给另一个组件。由于不推荐使用字符串引用,因此我使用回调引用。
So I have something similar to this:
所以我有类似的东西:
<One ref={c => this.one = c}/>
<Two one={this.one}/>
The problem is that whenever I try to access this.props.one
inside Two
I get undefined
.
问题是,每当我尝试访问this.props.one
内部时,Two
我都会得到undefined
.
I have even tried this on Two
:
我什至试过这个Two
:
componentDidMount(){
setTimeout(()=>{
console.log(this.props.one);
},5000)
}
It seems the problem is that when the prop is created, the ref doesn't exist yet since it's created once One
is mounted. But I don't know how to "refresh" the props on Two
to get the ref to the mounted component.
似乎问题在于,当创建 prop 时,ref 还不存在,因为它创建了一次就One
被挂载了。但我不知道如何“刷新”道具Two
以获取已安装组件的引用。
So what's the proper way of passing a ref to another component?
那么将 ref 传递给另一个组件的正确方法是什么?
Edit
编辑
Some users have suggested to encapsulate that logic in a higher component, which in itself renders those other child components.
一些用户建议将该逻辑封装在更高的组件中,该组件本身呈现那些其他子组件。
The problem with that approach is that you can't create reusable logic and you have to repeat the same logic over and over in those encapsulating components.
这种方法的问题在于您无法创建可重用的逻辑,并且必须在这些封装组件中一遍又一遍地重复相同的逻辑。
Let's say you want to create a generic <Form>
component which encapsulates the submit logic to your store, error checking, etc. And you do something like this:
假设您想创建一个通用<Form>
组件,该组件将提交逻辑封装到您的商店、错误检查等。您执行以下操作:
<Form>
<Input/>
<Input/>
<Input/>
<Input/>
<SubmitButton/>
</Form>
In this example <Form>
can't access the instances (and methods) of the children since this.props.children
doesn't return those instances. It returns some list of pseudo components.
在此示例<Form>
中,无法访问子项的实例(和方法),因为this.props.children
不返回这些实例。它返回一些伪组件列表。
So how can you check if a certain <Input/>
has detected a validation error without passing a ref?
那么如何在<Input/>
不传递 ref 的情况下检查某个人是否检测到验证错误?
You have to encapsulate those components in another component with the validation logic. For example in <UserForm>
. But since each form is different the same logic has to be copied in <CategoryForm>
, <GoupForm>
, etc. This is terribly inefficient which is why I want to encapsulate the validation logic in <Form>
and pass references of the <Input>
components to <Form>
.
您必须使用验证逻辑将这些组件封装在另一个组件中。例如在<UserForm>
. 但是由于每个表单都不同,因此必须在<CategoryForm>
、<GoupForm>
等中复制相同的逻辑。这是非常低效的,这就是我想将验证逻辑封装在 中<Form>
并将<Input>
组件的引用传递到 的原因<Form>
。
采纳答案by Carl Sverre
In general the "ref" feature is an anti-pattern in React. It exists to enable side-effect driven development, however in order to benefit the most from the React way of programming you should try to avoid "refs" if possible.
一般来说,“ref”特性是 React 中的一种反模式。它的存在是为了支持副作用驱动的开发,但是为了从 React 编程方式中获得最大收益,您应该尽可能避免“引用”。
As for your particular issue, passing a child a ref to it's sibling is a chicken vs. egg scenario. The ref callback is fired when the child is mounted, not during render which is why your example doesn't work. One thing you can try is pushing the ref into state and then reading from state into the other child. So:
至于你的特定问题,将一个孩子传递给它的兄弟姐妹是一个鸡与蛋的场景。ref 回调在孩子被挂载时触发,而不是在渲染期间触发,这就是您的示例不起作用的原因。您可以尝试的一件事是将 ref 推入状态,然后从状态读取到另一个孩子。所以:
<One ref={c => !this.state.one && this.setState({ one: c })}/>
<Two one={this.state.one}/>
Note: without the !this.state.one
this will cause an infinite loop.
注意:没有!this.state.one
this 会导致无限循环。
Here is a codepen example of this working (look at the console to see the sibling ref logged): http://codepen.io/anon/pen/pbqvRA
这是此工作的 codepen 示例(查看控制台以查看记录的兄弟参考):http: //codepen.io/anon/pen/pbqvRA
回答by kevin.groat
This is now much simpler using the new ref api(available since React 16 - thanks to perilandmishap for pointing that out).
现在使用新的 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>
}
}
}
You would consume the prop in Two
like:
你会Two
像这样消耗道具:
this.props.one.current
A few things of note with this approach:
这种方法有几点值得注意:
The ref will be an object with a current
property. That property will be null
until the element/component is mounted. Once it's mounted, it will be the instance of One
. It shouldbe safe to reference it once <Two />
is mounted.
ref 将是一个具有current
属性的对象。该属性将null
一直保持到元素/组件被安装。挂载后,它将是One
. 安装后引用它应该是安全的<Two />
。
Once the <One />
instance is unmounted, the current
property on the ref returns to being null
.
一旦<One />
实例被卸载时,current
在裁判回报是财产null
。
回答by Ben Mosher
In general, if you need to pass a reference to something that may not be set at call time, you can pass a lambda instead:
一般来说,如果你需要传递一个在调用时可能没有设置的引用,你可以传递一个 lambda:
<One ref={c => this.one = c}/>
<Two one={() => this.one}/>
and then reference it as
然后将其引用为
this.props.one()
If it has been set when you call it, you'll get a value. Before that, you'll get undefined
(assuming it hasn't otherwise been initialized).
如果在您调用它时已设置它,您将获得一个值。在此之前,你会得到undefined
(假设它没有被初始化)。
It bears noting that you won't necessarily re-render when it becomes available, and I would expect it to be undefined
on the first render. This is something that using state to hold your reference does handle, but you won't get more than one re-render.
值得注意的是,当它可用时你不一定会重新渲染,我希望它undefined
在第一次渲染时出现。这是使用 state 来保存您的参考确实可以处理的事情,但您不会获得多次重新渲染。
Given all that, I would recommend moving whatever code was using the ref to One
in Two
up into the component that is rendering One
and Two
, to avoid all the issues with both this strategy, and the one in @Carl Sverre's answer.
鉴于这一切,我会建议任何代码用的是裁判的移动One
中Two
成被渲染组件One
和Two
,以避免所有这两种策略,和一个在@Carl斯维尔的答案的问题。