Обновление дочернего состояния из родительского React

У меня есть таблица с некоторыми данными, и каждый элемент в таблице является компонентом класса React. Это выглядит так:

Таблица

Все, что я хочу, это иметь один флажок для функции «отметить все» (верхний левый флажок). Дело в том, что я не знаю, как это решить из-за props и state.

У меня есть такой код в компоненте с одним элементом:

getInitialState: function() {
    return { component: this.props.data };
  },

render: function() {
    var data = this.state.component;
    data = data.set('checked', this.props.data.get('checked'));
    ...
}

И я знаю, что не должен получать параметр checked от props, но это временно.

У меня проблема: когда я обновляю параметр checked в родительском, он не обновляет состояние, потому что getInitialState не вызывается после обновления (да, я знаю, что так и должно быть).

Мой вопрос: могу ли я как-то обновить состояние дочернего компонента? Или это лучший способ добиться этого.


person Tomasz Kasperek    schedule 24.04.2015    source источник


Ответы (4)


Мой подход заключается в том, что у вас должна быть примерно такая структура в родительском рендеринге:

<ParentView>
{ this.props.rows.map(function(row) {
    <ChildRow props={row.props} />
  }).bind(this)
}
</ParentView>

И затем на row.props у вас есть информация о том, отмечен ли текущий элемент строки или нет. Когда родительский флажок установлен, вы заполняете все row.props статусом.

На дочернем вы получите те, у кого есть componentWillReceiveProps, и вы сделаете волшебство (например, установите правильное состояние), когда флажок установлен:

componentWillReceiveProps: function(props) {
  this.setState({isChecked: props.isChecked});
}

(Информация из документации React: Вызов this.setState() внутри этой функции не вызовет дополнительный рендеринг.)

Визуализация дочернего элемента будет выглядеть примерно так:

<div>
  <input type='checkbox' checked={this.state.isChecked} />
  <label>{this.props.label}</label>
</div>
person Samuli Hakoniemi    schedule 24.04.2015
comment
Если вы не будете очень осторожны, вы можете закончить тем, что ребенок борется со своим родителем за контроль над своим состоянием. ИМХО, лучше сделать ребенка без гражданства и управлять им только реквизитом. Родитель может контролировать проверенное состояние всех дочерних элементов. - person edoloughlin; 24.04.2015
comment
@edoloughlin Спасибо, за ваш комментарий, он спас мне жизнь. - person ashbuilds; 08.05.2017

С функциональными компонентами. Простой способ обновить внутреннее состояние дочерних элементов, когда реквизиты, предоставленные родительским изменением, — через useEffect():

У детей:

const [data, setData] = useState(props.data);

useEffect( () => {
    setData(props.data);
}, [props.data]); 

Таким образом, каждый раз, когда props.data изменяется, useEffect будет запускаться и заставлять устанавливать новый статус для некоторых данных, и поэтому компонент будет обновляться.

person Luca Pelosi    schedule 13.12.2020
comment
Да, это то, что я искал. Спасибо. - person Rafał; 19.01.2021

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

Например, у ребенка:

render: function() {
    //... not showing other components...
        <input type="checkbox"
               value={this.props.value}
               checked={this.props.checked}
               onClick={this.props.onClick}>
}

Родитель предоставляет onClick, который изменяет проверенный статус дочернего элемента в его состоянии и передает его обратно дочернему элементу при повторном рендеринге.

В родительском:

getInitialState: function() {
    return {
        allChecked: false,
        childrenChecked: new Array(NUM_CHILDREN) // initialise this somewhere (from props?)
    }
},

render: function() {
    return <div>
               <input type="checkbox" checked={this.state.allChecked}>
               {children.map(function(child, i) {
                   return <Child checked={this.state.childrenChecked[i]}
                                 onClick={function(index) {
                                     return function() {
                                         // update this.state.allChecked and this.state.childrenChecked[index]
                                     }.bind(this)
                                 }.bind(this)(i)}
                          />
                }).bind(this)}
           </div>;
}

-- не проверяется на опечатки и т.д.

person edoloughlin    schedule 24.04.2015

См. документацию по реакции, посвященную подъему состояния. В вашем дочернем компоненте вам нужно использовать реквизит. Чтобы обновить проп, вам нужно предоставить функцию обновления от родителя.

person Duray Akar    schedule 30.11.2017