Jason Xu
Jason Xu

Reputation: 885

When using Immutable.JS, should redux selectors always return Immutable.JS objects?

The Redux Team suggests selectors always return Immutable.JS objects .However, I find it's difficult for selectors to return Immutable.JS objects when selectors' returning objects are constructed by multiple slices of the state.

Take the official shopping-cart demo as an example. The selector getCartProducts uses both the cart slice and the product slice of the state to construct the returning object:

export const getCartProducts = state =>
  getAddedIds(state).map(id => ({
    ...getProduct(state, id),
    quantity: getQuantity(state, id)
  }))

In this case, if using Immutable.JS, how to reconstruct this selector to let it return a Immutable.JS object?

Upvotes: 0

Views: 660

Answers (3)

aquilesb
aquilesb

Reputation: 2272

If your whole redux state is an immutable.js object, all those functions are going to return an immutable.js object. Per example, getAddedIds(state) function will return an Immutable.List and the map function will return a new Immutable.List. As you shouldn't never mix plain JS objects with Immutable.js objects, the objects inside those Lists will be an Immutable.js as well.

I tried to create a simple example to show you how these selectors would look like

const ids = [
  'a2ds2',
  'a3322asdda',
  '1d1w1s11x1'
];

const products = [{
  id: 'a2ds2',
  name: 'milk'
},
{
  id:'a3322asdda',
  name: 'bread'
},
{
  id:'b1d1w1s11x1',
  name: 'orange'
}
];

const cartItems = [
{
  productId: 'a3322asdda',
  qnt: 20
},
{
  productId: 'a2ds2',
  qnt: 3
}
]

const newState = Immutable.fromJS({
  ids, 
  products,
  cartItems
})

// returns an List of ids
const getAddedIds = (state) => state.get('ids').filter(id => id[0] === 'a')

// returns an product Map
const getProduct = (state, id) => state.get('products').find(product => product.get('id') === id)

// returns the qnt of a product
const getQntByProduct = (state, id) => state.get('cartItems').find(item => item.get('productId') === id).get('qnt')

// create the new List
const result = getAddedIds(newState)
  .map(id => getProduct(newState, id).set(
          'qnt', 
          getQntByProduct(newState, id)
        )
  )

console.log('result', result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.min.js"></script>

Upvotes: 0

Lukas Liesis
Lukas Liesis

Reputation: 26423

If you will use Immutable JS object and use method .map on it, it will return new ImmutableJs object.

https://facebook.github.io/immutable-js/docs/#/Map/map

If you have vanilla JS object and want to convert it to Immutable.js there is helper function fromJS() https://facebook.github.io/immutable-js/docs/#/fromJS

let some = {foo: 'bar'};
let immutableObject = Immutable.fromJS(some);

so couple options.

  1. make sure you are running map function on Immutable.js structure

  2. run as it is now and after done transfer from vanilla to Immutable.js using Immutable.fromJS()

Upvotes: 0

Gabriel Bleu
Gabriel Bleu

Reputation: 10224

It is important to not mutate the state, but you can do this without Immutable.JS

You do not need to use Immutable.JS with Redux. Plain JavaScript, if written correctly, is perfectly capable of providing immutability without having to use an immutable-focused library. redux faq

Upvotes: 2

Related Questions