0

So, I've been working on making an APP in React Native for which i have programmed a RESTFul API in Java, which returns some data in JSON format. I will have a datastructure that looks something like this - it is also the initial state for this Reducer, I have simply deleted some of the values as they are irrelevant:

categories: [{
    id: 1,
    name: '',
    image: '',
    subcategories: [
        {
            name: '',
            id: 1,
            products: [{
                name: '',
                description: 'This is a good product',
                id: 55,
                quantity: 4
            }, {
                name: '',
                description: 'This is a good product',
                id: 3,
                quantity: 0
            }]
        },
        {
            name: '',
            id: 2,
            products: [{
                name: '',
                description: 'This is a good product',
                id: 4,
                quantity: 0

            }]
        }]
}, {
    id: 2,
    name: '',
    image: '',
    subcategories: [
        {
            name: '',
            id: 3,
            products: [{
                name: '',
                description: 'This is a good product',
                id: 15,
                quantity: 0

            }]
        }

    ]
}]

I will be saving this in my Redux store but where i struggle is when I have to update the quantity of a certain product with only the products id. So far I've found a solution using immutable.js but it is quite ugly and I'm really unsure if this is the way to go.

I've searched for solutions but have not yet found one with a solution without normalizing the datastructure. For now I want to see if I can avoid normalizing the data, as I want to keep the same format for posting stuff back to the server. (and for learning purposes)

My solution in my Reducer with immutable.js looks like this:

case types.ADD_PRODUCT:

        const oldState = fromJS(state).toMap();

        var findCategoryIndex = oldState.get('categories').findIndex(function (category) {
            return category.get("subcategories").find(function (subcategories) {
                return subcategories.get("products").find(function (product) {
                    return product.get("id") === action.productId;
                })
            })
        })

        var findSubcategoryIndex = oldState.getIn(['categories', findCategoryIndex.toString()]).get('subcategories').findIndex(function (subcategory) {
            return subcategory.get("products").find(function (product) {
                return product.get("id") === action.productId;
            });
        })

        var findProductIndex = oldState.getIn(['categories', findCategoryIndex.toString(), 'subcategories', findSubcategoryIndex.toString()]).get('products').findIndex(function (product) {
                return product.get("id") === action.productId;
        })


        var newState = oldState.setIn(['categories', findCategoryIndex.toString(),
            'subcategories', findSubcategoryIndex.toString(), 'products', findProductIndex.toString(), 'quantity'],
        oldState.getIn(['categories', findCategoryIndex.toString(), 'subcategories', findSubcategoryIndex.toString(), 'products', findProductIndex.toString(), 'quantity'])+1);


        const newStateJS = newState.toJS();


        return {...state, categories: [...newStateJS.categories]}

I know all this may seem overcomplicated for the case, but I am simply trying to learn different approaches to this as I am very new to everything that has to do with JavaScript.

I am not looking for optimization on the data format itself, but I am looking for ways to manipulate data in nested arrays in Redux

I hope to get some good feedback on this and hopefully find out if I am on the right track :)

EDIT: It works with spread operators aswell without using Immutable.js, but I don't really understand what the difference is. Is there a performance difference and why choose one over the other?

case types.ADD_PRODUCT:
        return {
            ...state,
            categories:[...state.categories.map(category => ({...category,
                subcategories:[...category.subcategories.map(subcategory => ({...subcategory,
                    products:[...subcategory.products.map(product => product.id === action.productId ? {...product, quantity: product.quantity+1} : product)]}))]}))]
        }

1 Answer 1

3

When things the data to become a bit too deep, you can still use helper like Immutable.js Map. I am not sure this is the correct way to use Immutable.js since I am also experimenting it. It lets you return new state in a less verbose way like this :

import { fromJS } from 'immutable';

export default function reducer(state = initialState, action) {    
  const iState = fromJS(state);// Immutable State
  switch (action.type) {
    case type.ACTION:
      return iState.setIn(['depth1','depth2', 'depth3'], 'foobar').toJS() 
// return a copy of the state in JavaScript
// {depth1: {depth2: {depth3: 'foobar'} } }
  default:
    return state;
}

and from what I heard, using Immutable is more performant but it adds an another dependency to your project. Careful tough, if you are using combineReducers(reducers), it expects to be pass a plain object, so be sure to pass a plain object and not an Immutable object.

You said you are not specifically looking for optimization on the data format itself. Correct me if I am wrong, I think normalizr will help you to gain in flatness and be easier to update your store

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.