Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use .toJS() with Immutable.js and Flux?

I'm trying to use ImmutableJS with my React / Flux application.

My stores are Immutable.Map objects.

I'm wondering at which point should I use .toJS() ? Should it be when the store's .get(id) returns ? or in the components with .get('member') ?

like image 791
chollier Avatar asked Jan 09 '15 16:01

chollier


People also ask

What is toJS in JavaScript?

toJS() converts plain JS objects with a length property, in an Immutable collection, to an array (v4) #1438.

Why should we use immutable js?

Immutable. js is a library that supports an immutable data structure. It means that once created data cannot be changed. It makes maintaining immutable data structures easier and more efficient.

Why use immutable objects in react?

An immutable variable can never be changed. To update its value, you create a new variable. The same applies to objects and arrays. Instead of changing an array, to add a new item you create a new array by concatenating the old array, plus the new item.

What is fromJS in immutable?

fromJS() Deeply converts plain JS objects and arrays to Immutable Maps and Lists.


2 Answers

Ideally, never!

If your Flux stores are using Immutable.js then try to maintain all the way through. Use React.addons.ReactComponentWithPureRenderMixin to achieve a memoization performance win (it adds a shouldComponentUpdate methods).

When rendering, you may need to call toJS() as React v0.12.x only accepts Array as children:

render: function () {   return (     <div>       {this.props.myImmutable.map(function (item) {         <div>{item.title}</div>       }).toJS()}     </div>   ); } 

This have changed in React v0.13.x. Components accept any Iterable as children instead of only Array. Since Immutable.js implements Iterable, you are able to omit the toJS():

render: function () {   return (     <div>       {this.props.myImmutable.map(function (item) {         <div>{item.title}</div>       })}     </div>   ); } 
like image 94
Lee Byron Avatar answered Oct 06 '22 01:10

Lee Byron


Kinda old question but lately I've been experimenting with this approach using reselect and lodash's memoize in the effort of returning comparable objects to React's Components.

Imagine you have a store like this:

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

Then I pass to a TodoList component todos as a prop, which will then be mapped into two TodoItem Components:

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;     }      // ... } 

This way, if nothing changed in the todo's store, when I call getTodos() reselect returns to me the same object, and so nothing gets re-rendered.

If, for example, todo with id 2 is marked as completed, it also changes in the store, and so a new object is returned by todosSelector. Then the todos are mapped by memoizeTodo function, which should return the same object if a todo isn't changed (since they are Immutable Maps). So when TodoList receives the new props, it re-renders because todos has changed, but only the second TodoItem re-renders because the object representing the todo with id 1 didn't change.

This surely could lead to a performance loss, especially if our store contains a lot of items, but I didn't notice any problem in my medium-size app. The upside of this approach is that your Components receives plain javascript objects as props and could use them with something like PureRenderMixin, so how objects are returned from the store is not business of Components anymore.

like image 22
Ingro Avatar answered Oct 06 '22 00:10

Ingro