Ответ 1
===
проверяет, является ли он одним и тем же объектом. Кажется, что то, что вы делаете, изменяет значение, на которое указывает свойство boxes
.
У меня есть jsbin для этой проблемы здесь: http://jsbin.com/tekuluve/1/edit
В событии onClick я удаляю элемент из модели и повторно рендерирую приложение. Но как ни странно, в компонентахWillReceiveProps() (и componentWillUpdate и componentDidUpdate тоже) nextProps всегда === для this.props, независимо от того, что я делаю.
/** @jsx React.DOM */
var Box = React.createClass({
render: function() {
return (
<div className="box" onClick={ UpdateModel }>
{ this.props.label }
</div>
);
}
});
var Grid = React.createClass({
componentWillReceiveProps: function(nextProps) {
// WTF is going on here???
console.log(nextProps.boxes === this.props.boxes)
},
render: function() {
var boxes = _.map(this.props.boxes, function(d) {
return (<Box label={ d.number } />);
});
return (
<div className="grid">
{ boxes }
</div>
);
}
});
var model = [
{ number: 1 },
{ number: 2 },
{ number: 3 },
{ number: 4 },
{ number: 5 }
];
function UpdateModel() {
React.renderComponent(
<Grid boxes={ _.pull(model, _.sample(model)) } />,
document.body
);
}
React.renderComponent(
<Grid boxes={ model } />,
document.body
);
Мне нужно, чтобы nextProps отличались от this.props после того, как он был обновлен через UpdateModel(), в событии lifecycle компонента componentWillReceiveProps().
===
проверяет, является ли он одним и тем же объектом. Кажется, что то, что вы делаете, изменяет значение, на которое указывает свойство boxes
.
Что-то вроде этого произошло для меня, используя Flux Stores, чтобы сохранить мое состояние в соответствии с официальным руководством Todo List (http://facebook.github.io/flux/docs/todo-list.html), Для других, кто нашел это после выполнения учебника, проблема возникает в TodoStore в методе getAll(), потому что она возвращает прямую ссылку на внутренний объект данных:
getAll: function() {
return _todos;
}
Это, по-видимому, нарушает способность методов жизненного цикла, таких как componentDidUpdate (prevProps), различать старый и новый реквизиты. Я считаю, что причина заключается в том, что, передавая прямую ссылку на объект данных Store в представлениях, состояние/реквизит эффективно меняются сразу же после изменения Хранилища, а не после того, как новые значения передаются по методам жизненного цикла, поэтому старые и новые реквизиты всегда содержат те же значения. Это можно решить, передав копию внутреннего объекта данных _todos, а не самого объекта,
например, когда _todos является объектом,
getAll: function() {
return JSON.parse(JSON.stringify(_todos));
}
Если _todos является массивом, вместо него можно использовать _todos.slice().
В общем случае, если вы используете Store для хранения информации о состоянии и вызывают его из представлений вашего контроллера, представляется целесообразным вернуть копию данных, а не ссылку на оригинал, поскольку оригинал будет мутирован при изменении состояния происходят.
Вы можете использовать Immutable.js. Это библиотека, которую Facebook сделал для работы с реакцией/потоком. https://facebook.github.io/immutable-js/
Мы несколько раз сталкивались с этим.
shouldComponentUpdate(nextProps) {
return this.props.myObj !== nextProps.myObj
}
Много раз, некоторое значение внутри объекта myObj изменилось бы. Однако вышеприведенная функция вернет false. Причина в том, что оба this.props.myObj
и nextProps.myObj
ссылались/указывали на один и тот же объект.
Внедряя Immutable.js, данные всегда передаются вниз как клоны (вместо ссылки на один и тот же объект они фактически будут отдельными объектами).
Он повторно вводит однонаправленный поток потока. Вы никогда не сможете (случайно) изменить исходные данные, которые передаются в ваш компонент (будь то реквизит или из хранилища потоков).
Это также позволяет использовать PureRenderMixin - который автоматически останавливает рендер, если значения состояния/реквизита не изменились. Это может помочь в производительности.
Одной из альтернатив реализации Immutable.js является использование оператора распространения объектов.
В качестве примера,
предположим, что у вас есть переменная, которую вы хотите изменить, а затем выполните что-то с помощью
const obj1 = {a: 1, b: 2}
const obj2 = testObj
obj2.a: 3
// result: obj1 = obj2 = {a:3, b:2}
Исходный объект будет изменен. Это связано с тем, что переменная obj2 по существу является просто указателем на объект obj1.
Теперь предположим, что вместо этого мы используем оператор спреда
const obj1 = {a: 1, b: 2}
const obj2 = {...testObj}
obj2.a: 3
// result: obj1 = {a:1, b:2}, obj2 = {a:3, b:2}
Результатом этого будет то, что obj2 должным образом обновляется, но obj1 остается нетронутым. Оператор спреда эффективно создает неглубокий клон obj1. Я нашел, что оператор спреда будет особенно полезен при изменении состояния в редукторах редукции. Если вы установите переменные равными состоянию напрямую и внесите изменения, это вызовет проблему, с которой вы столкнулись.
Если вы не хотите использовать распространение, вы можете это сделать. Просто измените вашу функцию UpdateModel
на
UpdateModel(){
React.renderComponent(
<Grid boxes={ _.clone(_.pull(model, _.sample(model))) } />, document.body
);
}
В противном случае объект nextProp.boxes будет тем же объектом, что и объект this.props.boxes, поэтому любые изменения, внесенные вами в него, будут отражены в обоих.