我正在尝试将 ImmutableJS 与我的 React / Flux 应用程序一起使用。
我的商店是Immutable.Map
对象。
我想知道我应该在什么时候使用.toJS()
?应该是商店.get(id)
回来的时候吗?或在组件中.get('member')
?
我正在尝试将 ImmutableJS 与我的 React / Flux 应用程序一起使用。
我的商店是Immutable.Map
对象。
我想知道我应该在什么时候使用.toJS()
?应该是商店.get(id)
回来的时候吗?或在组件中.get('member')
?
理想情况下,永远不要!
如果您的 Flux 商店使用的是 Immutable.js,那么请尝试一直维护。使用 React.addons.ReactComponentWithPureRenderMixin 来实现记忆性能的胜利(它添加了一个 shouldComponentUpdate 方法)。
渲染时,您可能需要调用toJS()
React v0.12.x only accept Array
as children:
render: function () {
return (
<div>
{this.props.myImmutable.map(function (item) {
<div>{item.title}</div>
}).toJS()}
</div>
);
}
这在 React v0.13.x 中发生了变化。组件接受任何 Iterable 作为子级,而不仅仅是Array
. 由于 Immutable.js 实现了 Iterable,您可以省略toJS()
:
render: function () {
return (
<div>
{this.props.myImmutable.map(function (item) {
<div>{item.title}</div>
})}
</div>
);
}
有点老问题,但最近我一直在试验这种方法,使用reselect和lodash 的 memoize将可比较的对象返回给 React 的组件。
想象一下你有一个这样的商店:
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
作为 prop传递给它,然后它会被映射成两个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;
}
// ...
}
这样,如果 todo 的商店中没有任何变化,当我调用getTodos()
reselect 时会返回相同的对象,因此不会重新渲染任何内容。
例如,如果带有 id 的待办事项2
被标记为已完成,它也会在存储中发生变化,因此一个新对象由 返回todosSelector
。然后 todos 被memoizeTodo
函数映射,如果 todo 没有改变,它应该返回相同的对象(因为它们是不可变的映射)。因此,当TodoList
接收到新的 props 时,它会重新渲染,因为todos
已更改,但只有第二次TodoItem
重新渲染,因为表示 id 为 1 的待办事项的对象没有更改。
这肯定会导致性能损失,特别是如果我们的商店包含很多项目,但我没有注意到我的中型应用程序有任何问题。这种方法的好处是你的组件接收普通的 javascript 对象作为 props 并且可以将它们与类似的东西一起使用PureRenderMixin
,所以如何从商店返回对象不再是组件的业务。
就像@LeeByron 说的,你不应该打电话给toJS
. 在 React 0.14.* 下,调用map
ImmutableMap
可以正常工作并呈现,但最终会出现警告:
尚未完全支持将地图用作子项。这是一个可能会被删除的实验性功能。将其转换为键控 ReactElements 的序列/迭代。
为了解决这个问题,你可以打电话toArray()
给你Map
喜欢的人:
render () {
return (
<div>
{this.props.immutableMap.toArray().map(item => {
<div>{item.title}</div>
})}
</div>
)
}
将您的可迭代对象转换为数组并为 React 提供所需的内容。
@Hummlas 提出的好观点。
我个人在我的 React 组件中使用它,当我迭代集合以呈现子组件数组时:
this.props.myImmutableCollection.map(function(item, index) {
React.DOM.div null, item.get('title');
}).toJS();
如果您不使用 .toJS(),React 将不会将映射元素识别为组件数组。