何时使用.toJS()与Immutable.js和Flux?

我正在尝试使用ImmutableJS和我的React / Flux应用程序。

我的商店是Immutable.Map对象。

我想知道我应该在哪一点使用.toJS() ? 应该是当商店的.get(id)返回? 或与.get('member')

理想的是,永远不要!

如果您的Flux商店正在使用Immutable.js,那么请尽量保持完整。 使用React.addons.ReactComponentWithPureRenderMixin实现memoization性能赢(它增加了一个shouldComponentUpdate方法)。

渲染时,可能需要调用toJS()因为React v0.12.x只接受Array作为子对象:

 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> ); } 

有点古老的问题,但最近我正在试验这种方法,使用重新select和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,它将被映射到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()重新select返回给我同一个对象,所以没有得到重新呈现。

例如,如果将id 2 si标记为已完成的待办事项,它也会在商店中更改,因此新的对象将由todosSelector返回。 然后, memoizeTodo通过memoizeTodo函数进行映射,如果待办事项不变(因为它们是不可变的地图),应该返回相同的对象。 所以当TodoList收到新的道具时,它会重新渲染,因为待办事项已经改变,但是只有第二个TodoItem重新渲染,因为代表待办事项ID为1的对象没有改变。

这肯定会导致性能损失,特别是如果我们的商店包含很多项目,但我没有注意到我的中型应用程序中有任何问题。 这种方法的好处是你的组件接收纯JavaScript对象作为道具,并可以像PureRenderMixin一样使用它们,所以如何从商店返回对象不再是组件的业务。

希望这是有道理的,我的英语是非常糟糕的:/

就像@ LeeByron所说的,你不应该叫一个toJS 。 在React 0.14。*​​下,在不可变map上调用map将正常工作并呈现,但是最终会显示警告:

使用地图作为孩子还没有完全支持。 这是一个可能被删除的实验性function。 将其转换为键控ReactElements的序列/迭代。

为了解决这个问题,你可以在你的Map上调用toArray() ,如下所示:

 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将不会将映射元素识别为组件数组。

– 不再推荐 –
当使用Redux时,我倾向于让连接的mapStateToProps函数使用toJS()来转换不可变的结构,并允许我的反应组件使用道具作为javascript对象。