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()
).
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.
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.
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 a runValidation
boolean.
- as soon as
runValidation
is set to true, inside a setState( { 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 like if (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`)
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.
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, call this.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).
For an even more lengthy (and way more complicated) solution to form validation in react (with flux) you could check this article.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…