使用immutable.js在Redux中操作嵌套数组中的数据

Manipulating data in nested arrays in Redux with immutable.js

本文关键字:嵌套 数组 数据 操作 使用 js Redux immutable      更新时间:2023-09-26

因此,我一直在用React Native制作一个应用程序,为此我用Java编程了一个RESTFul API,它以JSON格式返回一些数据。我会有一个看起来像这样的数据结构——这也是这个Reducer的初始状态,我只是删除了一些不相关的值:

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
            }]
        }
    ]
}]

我会把它保存在我的Redux商店里,但当我不得不只用产品id更新某个产品的数量时,我会很挣扎。到目前为止,我已经找到了一个使用immutable.js的解决方案,但它非常丑陋,我真的不确定这是否是可行的。

我一直在寻找解决方案,但还没有找到一个不规范数据结构的解决方案。现在,我想看看是否可以避免对数据进行规范化,因为我想保持将内容发布回服务器的相同格式。(用于学习目的)

我的Reducer中的immutable.js解决方案如下:

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]}

我知道这一切在这种情况下可能看起来过于复杂,但我只是想学习不同的方法,因为我对JavaScript的一切都很陌生。

我不是在寻找数据格式本身的优化,但我正在寻找在Redux 中操作嵌套数组中的数据的方法

我希望能得到一些好的反馈,并希望能发现我是否走上了正确的道路:)

编辑:它也可以在不使用Immutable.js的情况下使用扩散运算符,但我真的不明白区别是什么。有性能差异吗?为什么要选择一个而不是另一个?

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)]}))]}))]
        }

当数据变得有点太深时,您仍然可以使用像Immutale.js Map这样的助手。我不确定这是使用Immutable.js的正确方式,因为我也在试验它。它可以让你以一种不那么冗长的方式返回新状态,比如:

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

据我所知,使用Immutable更具性能,但它为您的项目添加了另一个依赖项。小心,如果你使用combineReducers(reducers),它希望传递一个普通对象,所以一定要传递一个纯对象,而不是一个不可变对象。

你说你并没有专门寻求数据格式本身的优化。如果我错了,请纠正我,我认为normalizer将帮助您获得平面度,并更容易更新您的商店