我想用我的React/Flux应用程序使用ImmutableJS。何时使用.toJS()与Immutable.js和Flux?
我的店是Immutable.Map
对象。
我不知道在这一点,我应该使用.toJS()
?商店的.get(id)
是否应该返回?或在与.get('member')
的组件?通过@Hummlas提出
我想用我的React/Flux应用程序使用ImmutableJS。何时使用.toJS()与Immutable.js和Flux?
我的店是Immutable.Map
对象。
我不知道在这一点,我应该使用.toJS()
?商店的.get(id)
是否应该返回?或在与.get('member')
的组件?通过@Hummlas提出
好一点。
我personnally用它在我的反应的组分,当我遍历一个集合,以使子组件阵列:
this.props.myImmutableCollection.map(function(item, index) {
React.DOM.div null, item.get('title');
}).toJS();
如果你不使用.toJS(),阵营将无法识别映射元素作为组件数组。
理想的情况下,从来没有!
如果你的流量商店使用Immutable.js然后试图通过维持所有的方式。使用React.addons.ReactComponentWithPureRenderMixin实现memoization性能赢(它增加了一个shouldComponentUpdate方法)。
渲染时,您可能需要调用toJS()
为阵营v0.12.x只接受Array
儿童:
render: function() {
return (
<div>
{this.props.myImmutable.map(function (item) {
<div>{item.title}</div>
}).toJS()}
</div>
);
}
这已经改变作出反应v0.13.x.组件接受任何Iterable作为孩子,而不仅仅是Array
。由于Immutable.js实现可迭代,你可以省略toJS()
:
render: function() {
return (
<div>
{this.props.myImmutable.map(function (item) {
<div>{item.title}</div>
})}
</div>
);
}
- 不再推荐 -
当使用终极版我倾向于让我的连接mapStateToProps函数变换使用toJS不变的结构()并允许我的反应组件使用道具作为JavaScript对象。
但是,toJS将返回一个新的深度克隆对象。这不利于表演。 –
这是真的,但是使用类似重新选择的东西,只有当底层的不可变对象发生了变化时才能返回新对象。唯一的问题是嵌套数据。例如,如果地图列表中只有一个元素发生了变化,则会返回一个包含新对象的全新数组,并在每个子视图中触发一个渲染。随着不可改变,只有变化后的孩子才会重新呈现...... – Ingro
因为表现,我已经停止了我所建议的。 – walkerrandophsmith
有点古老的问题,但最近我正在试验这种方法,使用reselect和lodash's 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
作为支柱,其将在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()
重新选择返回给我同一个对象,所以没有重新呈现。
如果例如待办事项ID为2 SI标记为完成,它也改变了存储,所以一个新的对象被todosSelector
返回。然后,待办事项由memoizeTodo
函数映射,如果待办事项未更改(因为它们是不可变的地图),该函数应返回相同的对象。所以当TodoList
收到新的道具时,它会重新渲染,因为todos
已更改,但只有第二个TodoItem
重新渲染,因为表示id为1的待办事项的对象未更改。
这肯定会导致性能损失,特别是如果我们的商店包含很多项目,但我没有发现我的中型应用程序有任何问题。这种方法的好处是你的组件接收纯JavaScript对象作为道具,并可以像PureRenderMixin
一样使用它们,所以从商店返回对象的方式不再是组件的业务。
希望这是有道理的,我的英语非常糟糕:/
惊人的解决方案! –
像@LeeByron说,你不应该叫toJS
。下反应0.14 *,调用一个不变的Map
map
将工作和正确渲染,但你会最终了一个警告:
使用地图作为孩子还没有完全支持。这是一个可能会被删除的实验性功能。相反,将其转换为键控ReactElements的序列/迭代。
为了解决这个问题,你可以在你喜欢Map
打电话toArray()
:
render() {
return (
<div>
{this.props.immutableMap.toArray().map(item => {
<div>{item.title}</div>
})}
</div>
)
}
转换您可迭代到一个数组中,并给予阵营想要的东西。
谢谢你的回答一直在寻找这么久! – user2861799
@ user2861799不客气,很高兴帮助:) –
好问题。我不会在商店中做到这一点,因为如果你想用shouldComponentUpdate优化渲染,那么你就失去了进行简单对象比较(prevState!== this.state)的能力。 –
非常感谢,不要在商店中使用'toJS()'。 – chollier