Подтвердить что ты не робот

Измените состояние, когда свойства изменяются и сначала монтируются на функции React-Missing?

Я столкнулся с проблемой состояний, основанных на свойствах.

Сценарий

У меня есть компонентный родитель, который создает свойство передачи дочернему компоненту. Детский компонент реагирует в соответствии с полученным свойством. В React "единственный" способ изменить состояние компонента - использовать компоненты componentWillMount или componentDidMount и componentWillReceiveProps, насколько я видел (среди прочего, но сосредоточиться на них, потому что getInitialState только один раз выполняется).

Моя проблема/вопрос

Если я получаю новое свойство от родителя, и я хочу изменить состояние, будет выполняться только функция componentWillReceiveProps и разрешит мне выполнить setState. Render не позволяет setStatus.

Что делать, если я хочу установить состояние в начале и время получения нового свойства? Поэтому я должен установить его на getInitialState или componentWillMount/componentDidMount. Затем вам нужно изменить состояние в зависимости от свойств, используя componentWillReceiveProps.

Это проблема, когда ваше состояние сильно зависит от ваших свойств, что почти всегда. Что может стать глупым, потому что вам нужно повторить состояния, которые вы хотите обновить, в соответствии с новым свойством.

Мое решение

Я создал новый метод, который он вызвал на компонентеWillMount и на компонентеWillReceiveProps. Я не обнаружил, что какой-либо метод был вызван после того, как свойство было обновлено перед визуализацией, а также при первом подключении компонента. Тогда не было бы необходимости делать это глупое обходное решение.

В любом случае, здесь вопрос: нет лучшей опции для обновления состояния при получении или изменении нового свойства?

/*...*/
/**
 * To be called before mounted and before updating props
 * @param props
 */
prepareComponentState: function (props) {
    var usedProps = props || this.props;

    //set data on state/template
    var currentResponses = this.state.candidatesResponses.filter(function (elem) {
        return elem.questionId === usedProps.currentQuestion.id;
    });
    this.setState({
        currentResponses: currentResponses,
        activeAnswer: null
    });
},
componentWillMount: function () {
    this.prepareComponentState();
},
componentWillReceiveProps: function (nextProps) {
    this.prepareComponentState(nextProps);
},
/*...*/

Я чувствую себя немного глупо, я думаю, что я что-то теряю... Я думаю, есть еще одно решение для решения этой проблемы.

И да, я уже знаю об этом: https://facebook.github.io/react/tips/props-in-getInitialState-as-anti-pattern.html

4b9b3361

Ответ 1

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

render: function() {
  var currentResponses = this.state.candidatesResponses.filter(function (elem) {
    return elem.questionId === this.props.currentQuestion.id;
  });

  return ...; // use currentResponses instead of this.state.currentResponses
}

Однако в некоторых случаях может быть смысл кэшировать эти данные (например, подсчитать, что это слишком дорого), или вам просто нужно знать, когда реквизит установлен/изменен по какой-то другой причине. В этом случае я бы использовал в основном шаблон, который вы написали в своем вопросе.

Если вам действительно не нравится вводить текст, вы можете формализовать этот новый метод как mixin. Например:

var PropsSetOrChangeMixin = {
  componentWillMount: function() {
    this.onPropsSetOrChange(this.props);
  },

  componentWillReceiveProps: function(nextProps) {
    this.onPropsSetOrChange(nextProps);
  }
};

React.createClass({
  mixins: [PropsSetOrChangeMixin],

  onPropsSetOrChange: function(props) {
    var currentResponses = this.state.candidatesResponses.filter(function (elem) {
        return elem.questionId === props.currentQuestion.id;
    });

    this.setState({
      currentResponses: currentResponses,
      activeAnswer: null
    });
  },

  // ...
});

Конечно, если вы используете компоненты React, основанные на class, вам нужно будет найти какое-то альтернативное решение (например, наследование или пользовательские JS mixins), так как они не получают миксы Mix в стиле React прямо сейчас.

(Для чего это стоит, я думаю, что код намного яснее, используя явные методы, я бы, вероятно, написал его вот так:)

componentWillMount: function () {
  this.prepareComponentState(this.props);
},

componentWillReceiveProps: function (nextProps) {
  this.prepareComponentState(nextProps);
},

prepareComponentState: function (props) {
  //set data on state/template
  var currentResponses = this.state.candidatesResponses.filter(function (elem) {
    return elem.questionId === props.currentQuestion.id;
  });
  this.setState({
    currentResponses: currentResponses,
    activeAnswer: null
  });
},