Вызовите методы на дочерних компонентах React

Я хочу написать компонент Form, который может экспортировать метод для проверки его дочерних элементов. К сожалению, форма не "видит" какие-либо методы в своих дочерних элементах.

Вот как я определяю потенциальных детей формы:

var Input = React.createClass({
  validate: function() {
    ...
  },
});

И вот как я определяю класс 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;
  }
});

Я заметил, что я могу вызвать метод для дочернего компонента, используя refs, но я не могу вызвать метод через props.children.

Есть ли причина для такого поведения React?

Как я могу это исправить?

2 ответа

Решение

Техническая причина заключается в том, что на момент попытки доступа к дочернему компоненту они еще не существуют (в DOM). Они еще не были установлены. Они были переданы вашему<Form> компонент в качестве конструктора или метод в качестве класса реакции. (отсюда и название класса в React.createClass()).

Как вы указываете, это можно обойти с помощью ссылок, но я бы не рекомендовал это. Во многих случаях ссылки, как правило, являются ярлыками для чего-то, для чего реакция не предназначена, и поэтому их следует избегать.

Вероятно, именно благодаря этой реакции родители затрудняют / делают невозможным доступ родителей к методам ребенка. Они не должны. Методы ребенка должны быть в ребенке, если они являются частными по отношению к ребенку: они делают что-то внутри ребенка, что не должно быть напрямую передано наверх к родителю. Если бы это было так, то обработка должна была быть сделана внутри родителя. Потому что родитель имеет по крайней мере всю информацию и данные, которые есть у ребенка.

Теперь, в вашем случае, я представляю, что у каждого входного (дочернего) компонента есть какой-то определенный метод проверки, который проверяет входное значение и, основываясь на результате, отправляет сообщение об ошибке. Скажем, красный контур вокруг неправильных полей.

Реакционным путем это может быть достигнуто следующим образом:

  • <Form> компонент имеет состояние, которое включает в себя runValidation логическое значение.
  • как только runValidation установлен в true, внутри setState( { runValidation: true }); Реакция автоматически перерисовывает всех детей.
  • если вы включите runValidation как опора для всех детей.
  • тогда каждый ребенок может проверить внутри своих render() функционировать с чем-то вроде if (this.props.runValidation) { this.validate() }
  • который выполнит validate() функция у ребенка
  • функция validate может даже использовать состояние ребенка (состояние не изменяется при входе новых реквизитов) и использовать его для сообщения проверки (например, "пожалуйста, добавьте более сложные символы в свой пароль")

Теперь это еще не исправлено: вы можете захотеть провести некоторую проверку на уровне формы после того, как все дети подтвердят себя: например, когда все дети в порядке, отправьте форму.

Чтобы решить эту проблему, вы можете применить ярлык ссылки для окончательной проверки и отправки. И реализовать метод в вашем <Form> внутри componentDidUpdate() функция, чтобы проверить, если каждый ребенок в порядке (например, имеет зеленую рамку) И, если нажмите кнопку отправить, а затем отправить. Но, как правило, я настоятельно рекомендую не использовать ссылки.

Для окончательной проверки формы, лучший подход:

  • добавьте переменную без состояния внутри вашего <Form> который содержит логические значения для каждого ребенка. Обратите внимание, что он должен быть не государственным, чтобы дети не могли запустить новый цикл рендеринга.
  • передать validateForm функционировать в качестве (обратного вызова) опоры для каждого ребенка.
  • внутри validate() в каждом ребенке звони this.props.validateForm(someChildID) который обновляет соответствующий логический параметр в переменной в форме.
  • в конце validateForm Функция в форме, проверьте, все ли логические значения верны, и если да, отправьте форму (или измените состояние формы или что-то еще).

Чтобы найти более продолжительное (и более сложное) решение для формирования валидации в реакции (с потоком), вы можете проверить эту статью.

Я не уверен, что что-то упустил, но, попробовав то, что предложил @wintvelt, я сталкивался с проблемой всякий раз, когда звонил runValidation метод внутри метода рендеринга React, так как в моем случае runValidation меняет состояние по телефону setState в нем, таким образом, вызывая метод рендеринга, который, очевидно, является плохой практикой, так как метод рендеринга должен быть чистым, и если я положу runValidation в willReceiveProps это не будет вызвано в первый раз, потому что if условие еще не выполнено (это условие изменяется в родительском компоненте с помощью setState, но в первом звонке willReceiveProps это все еще ложь).

Другие вопросы по тегам