javascript 在 React 子组件上调用方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33487740/
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
Call methods on React children components
提问by Ivan Mushketyk
I want to write a Form component that can export a method to validate its children. Unfortunately a Form does not "see" any methods on its children.
我想编写一个可以导出方法来验证其子项的 Form 组件。不幸的是,一个 Form 没有“看到”它的孩子的任何方法。
Here is how I define a potential children of Form:
以下是我如何定义 Form 的潜在子级:
var Input = React.createClass({
validate: function() {
...
},
});
And here is how I define Form class:
这是我定义 Form 类的方式:
var Form = React.createClass({
isValid: function() {
var valid = true;
this.props.children.forEach(function(component) {
// --> This iterates over all children that I pass
if (typeof component.validate === 'function') {
// --> code never reaches this point
component.validate();
valid = valid && component.isValid();
}
});
return valid;
}
});
I noticed that I can call a method on a child component using refs, but I cannot call a method via props.children.
我注意到我可以使用 refs 在子组件上调用一个方法,但我不能通过 props.children 调用一个方法。
Is there a reason for this React behaviour?
这种 React 行为是否有原因?
How can I fix this?
我怎样才能解决这个问题?
回答by wintvelt
The technical reason is that at the time you try to access the child component, they do not yet really exist (in the DOM). They have not been mounted yet. They have been passed to your<Form>
component as a constructor prop or method as a react class. (hence the name class in React.createClass()
).
技术原因是,当您尝试访问子组件时,它们还不存在(在 DOM 中)。它们尚未安装。它们已<Form>
作为构造函数 prop 或方法作为反应类传递给您的组件。(因此名称类在React.createClass()
)。
As you point out, this can be circumvented by using refs, but I would not recommend it. In many cases, refs tend to be shortcuts for something that react wasn't intended for, and therefore should be avoided.
正如您所指出的,这可以通过使用 refs 来规避,但我不推荐它。在许多情况下,refs 往往是不打算用于 react 的东西的捷径,因此应该避免。
It is probably by design that react makes it hard/ impossible for parents to access a child's methods. They are not supposed to. The child's methods should be in the child if they are private to the child: they do something inside the child that should not directly be communicated upward to the parent. If that were the case, than handling should have been done inside the parent. Because the parent has at least all info and data the child has.
React 可能是有意设计的,让父母很难/不可能访问孩子的方法。他们不应该这样做。如果孩子的方法对孩子来说是私有的,那么孩子的方法应该在孩子中:他们在孩子内部做一些不应该直接向上传达给父母的事情。如果是这种情况,那么处理应该在父级内部完成。因为父母至少拥有孩子拥有的所有信息和数据。
Now in your case, I imagine each input (child) component to have some sort of specific validation method, that checks the input value, and based on outcome, does some error message feedback. Let's say a red outline around incorrect fields.
现在在你的情况下,我想象每个输入(子)组件都有某种特定的验证方法,检查输入值,并根据结果,做一些错误消息反馈。假设在不正确的字段周围有一个红色轮廓。
In the react way, this could be achieved as follows:
在反应方式中,这可以实现如下:
- the
<Form>
component has state, which includes arunValidation
boolean. - as soon as
runValidation
is set to true, inside asetState( { runValidation: true });
react automatically re-renders all children. - if you include
runValidation
as a prop to all children. - then each child can check inside their
render()
function with something likeif (this.props.runValidation) { this.validate() }
- which will execute the
validate()
function in the child - the validate function can even use the child's state (state is not changed when new props come in), and use that for the validation message (e.g. 'please add more complicated symbols to your password`)
- 该
<Form>
组分具有的状态,其中包括一个runValidation
布尔值。 - 一旦
runValidation
设置为 true,在setState( { runValidation: true });
react 中会自动重新渲染所有子项。 - 如果您
runValidation
将所有孩子作为道具包括在内。 - 然后每个孩子都可以
render()
用类似的东西检查他们的功能if (this.props.runValidation) { this.validate() }
- 这将
validate()
在孩子中执行该功能 - 验证函数甚至可以使用孩子的状态(新道具进入时状态不会改变),并将其用于验证消息(例如“请向您的密码添加更复杂的符号”)
Now what this does not yet fix, is that you may want to do some checking at form level after all children have validated themselves: e.g. when all children are OK, submit the form.
现在这还没有解决的是,您可能希望在所有孩子都验证自己后在表单级别进行一些检查:例如,当所有孩子都正常时,提交表单。
To solve that, you could apply the refs shortcut to the final check and submit. And implement a method in your <Form>
inside a componentDidUpdate()
function, to check if each child is OK (e.g. has green border) AND if submit is clicked, and then submit. But as a general rule, I strongly recommend against using refs.
要解决这个问题,您可以将 refs 快捷方式应用于最终检查并提交。并在你<Form>
的componentDidUpdate()
函数内部实现一个方法,检查每个孩子是否正常(例如有绿色边框)以及是否点击提交,然后提交。但作为一般规则,我强烈建议不要使用 refs。
For final form validation, a better approach is:
对于最终的表单验证,更好的方法是:
- add a non-state variable inside your
<Form>
which holds booleans for each child. NB, it has to be non-state, to prevent children from triggering a new render cycle. - pass a
validateForm
function as a (callback) prop to each child. - inside
validate()
in each child, callthis.props.validateForm(someChildID)
which updates the corresponding boolean in the variable in the Form. - at the end of the
validateForm
function in the Form, check if all booleans are true, and if so, submit the form (or change Form state or whatever).
- 在您的内部添加一个非状态变量,
<Form>
其中包含每个孩子的布尔值。注意,它必须是非状态的,以防止孩子触发新的渲染周期。 - 将
validateForm
函数作为(回调)道具传递给每个孩子。 validate()
在每个孩子里面,调用this.props.validateForm(someChildID)
它更新表单中变量中相应的布尔值。- 在
validateForm
表单函数的末尾,检查所有布尔值是否为真,如果是,提交表单(或更改表单状态或其他)。
For an even more lengthy (and way more complicated) solution to form validation in react (with flux) you could check this article.
对于更冗长(且方式更复杂)的反应(使用通量)中的表单验证解决方案,您可以查看这篇文章。
回答by Elias Ghali
I'm not sure if i'm missing something, but after trying what @wintvelt suggested i ran into a problem whenever i called the runValidation
method inside the render method of React, since in my case runValidation
changes the state by calling setState
in it, thus triggering the render method which obviously is a bad practice since render method must be pure, and if i put the runValidation
in willReceiveProps
it won't be called the first time because the if
condition is not true yet (this condition is changed in the parent component using setState
, but in the first call of willReceiveProps
it's still false).
我不确定我是否遗漏了什么,但是在尝试了@wintvelt 建议的内容之后,每当我在runValidation
React 的渲染方法中调用该方法时,我都会遇到问题,因为在我的情况下runValidation
,通过调用setState
它来更改状态,从而触发渲染方法显然是一个不好的做法,因为渲染方法必须是纯的,如果我把它放进去runValidation
,willReceiveProps
它不会第一次被调用,因为if
条件还不为真(这个条件在父组件中使用setState
,但是在willReceiveProps
它的第一次调用中它仍然是错误的)。