Регенерация дочернего регенератора в React.js
Компонент Parent (MyList
в моем примере) отображает массив через MyComponent
компонент (MyComponent
). Родитель решает изменить свойства в массиве. Что такое React-способ запуска дочернего повторного рендеринга?
Все, что я придумал, это this.setState({});
в родительской после настройки данных. Это хак или React способ запуска обновления?
JS Fiddle: https://jsfiddle.net/69z2wepo/7601/
var items = [
{id: 1, highlighted: false, text: "item1"},
{id: 2, highlighted: true, text: "item2"},
{id: 3, highlighted: false, text: "item3"},
];
var MyComponent = React.createClass({
render: function() {
return <div className={this.props.highlighted ? 'light-it-up' : ''}>{this.props.text}</div>;
}
});
var MyList = React.createClass({
toggleHighlight: function() {
this.props.items.forEach(function(v){
v.highlighted = !v.highlighted;
});
// Children must re-render
// IS THIS CORRECT?
this.setState({});
},
render: function() {
return <div>
<button onClick={this.toggleHighlight}>Toggle highlight</button>
{this.props.items.map(function(item) {
return <MyComponent key={item.id} text={item.text} highlighted={item.highlighted}/>;
})}
</div>;
}
});
React.render(<MyList items={items}/>, document.getElementById('container'));
Ответы
Ответ 1
Проблема заключается в том, что вы сохраняете состояние в this.props
вместо this.state
. Поскольку этот компонент мутирует items
, items
является состоянием и должен храниться в this.state
. (Здесь хорошая статья о реквизитах против состояния.) Это решает проблему рендеринга, потому что когда вы обновляете items
, вы вызываете setState
, что автоматически вызвать повторную визуализацию.
Здесь ваш компонент будет выглядеть с использованием состояния вместо реквизита:
var MyList = React.createClass({
getInitialState: function() {
return { items: this.props.initialItems };
},
toggleHighlight: function() {
var newItems = this.state.items.map(function (item) {
item.highlighted = !item.highlighted;
return item;
});
this.setState({ items: newItems });
},
render: function() {
return (
<div>
<button onClick={this.toggleHighlight}>Toggle highlight</button>
{ this.state.items.map(function(item) {
return <MyComponent key={item.id} text={item.text}
highlighted={item.highlighted}/>;
}) }
</div>
);
}
});
React.render( <MyList initialItems={initialItems}/>,
document.getElementById('container') );
Обратите внимание, что я переименовал items
prop в initialItems
, потому что он ясно показывает, что MyList
будет мутировать его. Это рекомендуется по документации.
Вы можете увидеть обновленную скрипту здесь: https://jsfiddle.net/kxrf5329/
Ответ 2
Вы должны вызвать повторный рендеринг, вызвав setState()
и предоставив новый реквизит, который вы хотите распространять.
Если вы действительно хотите принудительно выполнить обновление, вы также можете вызвать forceUpdate()
.
Если вы посмотрите на примеры на странице, вы увидите, что setState
- это метод, используемый для обновления и запуска повторного использования, рендеринг. Документация также четко указывает (ahaha!).
В вашем случае я бы назвал forceUpdate
.
РЕДАКТИРОВАТЬ: Как отметила Иордания в комментарии, было бы лучше хранить предметы как часть вашего государства. Таким образом вам не нужно было бы вызывать forceUpdate
, но вы действительно обновили бы состояние своего компонента, поэтому регулярный setState
с обновленными значениями будет работать лучше.