0

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?

Jason Xu
  • 845
  • 8
  • 22

3 Answers3

2

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

Gabriel Bleu
  • 9,703
  • 2
  • 30
  • 43
  • I know how to write immutable state without immutable-focused library. But I wonder how to deal with the case mentioned in my question when using Immutable.JS. That's my question. – Jason Xu Nov 07 '17 at 03:05
0

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

Lukas Liesis
  • 24,652
  • 10
  • 111
  • 109
  • Thanks. But maybe you did't get my point. My point is whether selectors should always return Immutable.JS objects when using Immutable.JS or not ? In the case I mentioned, It seems selectors returning a plain JS Object is more reasonable. – Jason Xu Nov 07 '17 at 07:15
  • If you have immutable.js structure it will return immutable.js objects or node values. If node value is js object, it will return js object. – Lukas Liesis Nov 08 '17 at 08:32
0

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>
aquilesb
  • 2,182
  • 1
  • 19
  • 19