何时使用带有Immutable.js和Flux的.toJS()?

时间:2015-01-09 16:13:35

标签: reactjs reactjs-flux immutable.js

我试图在我的React / Flux应用程序中使用ImmutableJS。

我的商店是Immutable.Map个对象。

我想知道在哪一点上我应该使用.toJS()?应该是商店.get(id)何时返回?或者在.get('member')

的组件中

5 个答案:

答案 0 :(得分:44)

理想情况下,永远不要!

如果您的Flux商店使用的是Immutable.js,那么请尽量保持。使用React.addons.ReactComponentWithPureRenderMixin实现memoization performance win(它添加了一个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>
  );
}

答案 1 :(得分:4)

有点老问题,但最近我一直在尝试使用reselectlodash's memoize这种方法来努力将类似对象返回到React的组件。

想象一下,你有这样的商店:

execute

然后我传递给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组件:

TodoItem

这样,如果在todo的商店中没有任何改变,当我调用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; } // ... } 时,重新选择会向我返回相同的对象,因此不会重新渲染任何内容。

例如,如果标识为getTodos()的待办事项标记为已完成,则它也会在商店中更改,因此2会返回一个新对象。然后todos由todosSelector函数映射,如果todo没有改变,它应返回相同的对象(因为它们是不可变映射)。因此,当memoizeTodo收到新道具时,它会重新渲染,因为TodoList已更改,但只有第二个todos重新渲染,因为代表ID为1的待办事项的对象没有更改。

这肯定会导致性能下降,特别是如果我们的商店包含很多项目,但我没有发现我的中型应用程序有任何问题。这种方法的好处是你的组件接收普通的javascript对象作为道具,并且可以像TodoItem那样使用它们,所以如何从商店返回对象不再是组件的业务。

答案 2 :(得分:3)

就像@LeeByron所说,你不应该打电话给toJS。在React 0.14。*​​下,在不可变map上调用Map将正常工作并呈现,但您最终会收到警告:

  

尚未完全支持将地图用作子项。这是一个可能被删除的实验性功能。将其转换为键控ReactElements的序列/迭代。

要处理此问题,您可以在toArray()上致电Map,如:

render () {
  return (
    <div>
      {this.props.immutableMap.toArray().map(item => {
        <div>{item.title}</div>
      })}
    </div>
  )
}

将您的iterable转换为数组并为React提供它想要的内容。

答案 3 :(得分:2)

@Hummlas提出的好点。

当我遍历集合以呈现子组件数组时,我个人在我的React组件中使用它:

this.props.myImmutableCollection.map(function(item, index) {
    React.DOM.div null, item.get('title');
}).toJS();

如果你不使用.toJS(),React将不会将映射的元素识别为组件数组。

答案 4 :(得分:0)

- 不再推荐 -
当使用Redux时,我倾向于让我的连接'mapStateToProps函数使用toJS()转换不可变结构,并允许我的react组件将props作为javascript对象使用。