Собственный старый вопрос, но в последнее время я экспериментирую с этим подходом, используя reselect и lodash's memoize в попытке вернуть сопоставимые объекты в компоненты React's.
Представьте иметь магазин как это:
import { List, Map } from 'immutable';
import { createSelector } from 'reselect';
import _ from 'lodash';
const store = {
todos: List.of(
Map({ id: 1, text: 'wake up', completed: false }),
Map({ id: 2, text: 'breakfast', completed: false })
)
};
const todosSelector = state => state.todos;
function normalizeTodo(todo) {
// ... do someting with todo
return todo.toJS();
}
const memoizeTodo = _.memoize(normalizeTodo);
export const getTodos = createSelector(
todosSelector,
todos => todos.map(memoizeTodo)
);
Тогда я прохожу к TodoList
компонента todos
в качестве опоры, которая будет отображенный в 2 TodoItem
Компоненты:
class TodoList extends React.Component {
shouldComponentUpdate(nextProps) {
return this.props.todos !== nextProps.todos;
}
render() {
return (<div>
{this.props.todos.map(todo => <TodoItem key={todo.id} todo={todo} />)}
</div>);
}
}
class TodoItem extends React.Component {
shouldComponentUpdate(nextProps) {
return this.props.todo !== nextProps.todo;
}
// ...
}
Таким образом, , если ничего не изменилось в магазине todos, когда я вызываю getTodos()
reselect возвращает мне тот же объект, и поэтому ничего не перерисовывается.
Если, например, todo с id 2 si, отмеченное как завершенное, оно также изменяется в магазине, и поэтому новый объект возвращается todosSelector
. Затем todos отображаются функцией memoizeTodo
, которая должна возвращать тот же объект, если todo не изменяется (поскольку они являются неизменяемыми картами).Поэтому, когда TodoList
получает новые реквизиты, он повторно рендерится, потому что todos
изменился, но только второй TodoItem
повторный рендер, потому что объект, представляющий todo с id 1, не изменился.
Это, безусловно, может привести к потере производительности, особенно если наш магазин содержит много предметов, но я не заметил никаких проблем в своем приложении среднего размера. Поверхность этого подхода заключается в том, что ваши компоненты получают простые javascript-объекты в качестве реквизита и могут использовать их с чем-то вроде PureRenderMixin
, поэтому, как объекты возвращаются из магазина, больше не занимается компонентами.
Надеется, что это имеет смысл, мой английский очень плохо:/
Хороший вопрос. Я бы не делал этого в магазине, хотя, с тех пор вы теряете способность выполнять простое сравнение объектов (prevState! == this.state), если вы хотите оптимизировать рендеринг с shouldComponentUpdate. –
Спасибо, действительно, это хороший момент, чтобы не использовать 'toJS()' в магазинах. – chollier