更新嵌套状态对象中的单个记录,react-redux
Update single record in nested state object, react-redux
我正在开发一个网格结构,用户可以在其中动态添加部分、子部分或项目。我在我的 redux 状态对象中管理这些东西。 UI 我的网格如下:
我想更新单行记录而不是重新加载整个网格。为此,每当用户更改我正在调用 update-row
api 的行的任何单元格值时,如果成功,我将尝试使用以下代码在 reducer 中更新该值。
case UPDATE_ORDER_LINES_SUCCESS:
let stateData = state.get(`GridData`);
const dataIndex = stateData.children.findIndex(
(listing) => listing.id === action.row.id // row id which is updated
);
stateData[0].children[dataIndex] = action.row;
let data = Object.assign(stateData, { children: stateData.children });
state = state.set(`GridData`, [data]);
此代码对于第一级子记录(根据 json 对象)工作正常,但如果用户更新第 n 级子记录的值,则会出现问题。如何在我的 redux 状态下更新该行记录?
我当前的 redux 状态样本是:
{
"views": [
{
"id": "5e6b8961ba08180001a10bb6",
"viewName": "house",
"description": "house view",
"name": "house",
"children": [
{
"id": "5e6b8961ba08180001a10bb7",
"viewName": "house",
"sectionName": "Temporary",
"sectionId": "SEC-02986",
"description": "Temporary",
"sequenceNumber": 4,
"refrenceId": "SEC-02986",
"children": [
{
"id": "5e590df71bbc71000118c109",
"lineDescription": "AutoPickPack01",
"lineAction": "Rent",
"quantity": 5,
"deliveryDate": "2020-02-29T06:00:00+11:00",
"pickDate": "2020-02-28T06:00:00+11:00",
"pickupDate": "2020-03-01T06:00:00+11:00",
"prepDate": "2020-02-28T06:00:00+11:00",
"returnDate": "2020-03-01T06:00:00+11:00",
"shippingDate": "2020-02-29T06:00:00+11:00",
"unitPrice": 7000,
"children": [
{
"id": "5e590df71bbc71000118c10a",
"orderId": "Ord-05788_1",
"lineNumber": "01a7b77c-792a-4edb-9b73-132440621968",
"purchaseOrderNumber": null,
"lineDescription": "29Janserial",
"lineAction": "Rent",
"quantity": 5,
"pricingMethod": "Fixed",
"displayUnit": "Days",
"unitPrice": 0,
"chargeAmount": 0,
"pickDate": "2020-02-17T06:00:00+11:00",
"prepDate": "2020-02-28T06:00:00+11:00",
"shippingDate": "2020-02-29T06:00:00+11:00",
"deliveryDate": "2020-02-29T06:00:00+11:00",
"pickupDate": "2020-03-01T06:00:00+11:00",
"returnDate": "2020-03-01T06:00:00+11:00",
"name": "29Janserial",
"description": "29Janserial",
"discountAmount": "",
"discountPrice": ""
}
]
}
]
}
]
}
]
}
在 reducer 中更新嵌套子行数据的最佳方法是什么?
您应该规范化您的状态,这会使树变平,并且实体通过 id 引用关联而不是直接嵌套。
例如
{
"entities": {
"orders": {
"o1": { "id": "o1", "productIds": ["p1", "p2"] },
"o2": { "id": "o2", "productIds": ["p2", "p3"] },
"o3": { "id": "o2", "productIds": ["p3"] }
},
"products": {
"p1": { "id": "p1", "orderIds": ["o1"] },
"p2": { "id": "p1", "orderIds": ["o1", "o2"] },
"p3": { "id": "p1", "orderIds": ["o2", "o3"] }
},
"views": {
"v1": { "id": "v1", "childIds": ["v1.1", "v1.2"] },
"v1.1": { "id": "v1.1", "parentId": "v1" },
"v1.2": { "id": "v1.2", "parentId": "v1" }}
},
"ids": {
"orders": ["o1", "o2", "o3"],
"products": ["p1", "p2", "p3"],
"views": ["v1", "v1.1", "v1.2"]
}
}
找到正确模型并将原始数据转换为模型的前期工作较多,但您可以节省大量时间,而不必处理嵌套或影响多个数据区域的更新。
由于 redux 不允许改变当前状态并 return 返回,因此很难修改嵌套的子级。尽管非常不鼓励
在 redux 中有这种嵌套结构,而应该将其规范化为 @bsapaka 回答。但是如果你仍然想更新嵌套
对象和 return 整个状态作为一个不可变的状态,immer
应该是你的朋友。 immerJS
在处理不可变 states.Although
方面非常受欢迎
在你的案例中安装 immer 和 redux-immer
yarn add immer redux-immer
在您的 reducers.js
文件中,所有减速器已使用 combineReducers
组合
import produce from 'immer';
import { combineReducers } from 'redux-immer';
// Replace your current combineReducers with
combineReducers(produce, { /* Object of all reducers */ });
在你当前的reducer文件中
import product from 'immer';
const findNestedChild = (arr, itemId) => (
arr.reduce((a, item) => {
if (a) return a;
if (item.id === itemId) return item;
if (item['children']) return findItemNested(item['children'], itemId)
}, null)
);
case UPDATE_ORDER_LINES_SUCCESS:
return produce(state, draftState => {
const { row: newChild, row: { id }} = action;
let child = findNestedChild(draftState.views, id);
child = newChild;
});
我正在开发一个网格结构,用户可以在其中动态添加部分、子部分或项目。我在我的 redux 状态对象中管理这些东西。 UI 我的网格如下:
我想更新单行记录而不是重新加载整个网格。为此,每当用户更改我正在调用 update-row
api 的行的任何单元格值时,如果成功,我将尝试使用以下代码在 reducer 中更新该值。
case UPDATE_ORDER_LINES_SUCCESS:
let stateData = state.get(`GridData`);
const dataIndex = stateData.children.findIndex(
(listing) => listing.id === action.row.id // row id which is updated
);
stateData[0].children[dataIndex] = action.row;
let data = Object.assign(stateData, { children: stateData.children });
state = state.set(`GridData`, [data]);
此代码对于第一级子记录(根据 json 对象)工作正常,但如果用户更新第 n 级子记录的值,则会出现问题。如何在我的 redux 状态下更新该行记录?
我当前的 redux 状态样本是:
{
"views": [
{
"id": "5e6b8961ba08180001a10bb6",
"viewName": "house",
"description": "house view",
"name": "house",
"children": [
{
"id": "5e6b8961ba08180001a10bb7",
"viewName": "house",
"sectionName": "Temporary",
"sectionId": "SEC-02986",
"description": "Temporary",
"sequenceNumber": 4,
"refrenceId": "SEC-02986",
"children": [
{
"id": "5e590df71bbc71000118c109",
"lineDescription": "AutoPickPack01",
"lineAction": "Rent",
"quantity": 5,
"deliveryDate": "2020-02-29T06:00:00+11:00",
"pickDate": "2020-02-28T06:00:00+11:00",
"pickupDate": "2020-03-01T06:00:00+11:00",
"prepDate": "2020-02-28T06:00:00+11:00",
"returnDate": "2020-03-01T06:00:00+11:00",
"shippingDate": "2020-02-29T06:00:00+11:00",
"unitPrice": 7000,
"children": [
{
"id": "5e590df71bbc71000118c10a",
"orderId": "Ord-05788_1",
"lineNumber": "01a7b77c-792a-4edb-9b73-132440621968",
"purchaseOrderNumber": null,
"lineDescription": "29Janserial",
"lineAction": "Rent",
"quantity": 5,
"pricingMethod": "Fixed",
"displayUnit": "Days",
"unitPrice": 0,
"chargeAmount": 0,
"pickDate": "2020-02-17T06:00:00+11:00",
"prepDate": "2020-02-28T06:00:00+11:00",
"shippingDate": "2020-02-29T06:00:00+11:00",
"deliveryDate": "2020-02-29T06:00:00+11:00",
"pickupDate": "2020-03-01T06:00:00+11:00",
"returnDate": "2020-03-01T06:00:00+11:00",
"name": "29Janserial",
"description": "29Janserial",
"discountAmount": "",
"discountPrice": ""
}
]
}
]
}
]
}
]
}
在 reducer 中更新嵌套子行数据的最佳方法是什么?
您应该规范化您的状态,这会使树变平,并且实体通过 id 引用关联而不是直接嵌套。
例如
{
"entities": {
"orders": {
"o1": { "id": "o1", "productIds": ["p1", "p2"] },
"o2": { "id": "o2", "productIds": ["p2", "p3"] },
"o3": { "id": "o2", "productIds": ["p3"] }
},
"products": {
"p1": { "id": "p1", "orderIds": ["o1"] },
"p2": { "id": "p1", "orderIds": ["o1", "o2"] },
"p3": { "id": "p1", "orderIds": ["o2", "o3"] }
},
"views": {
"v1": { "id": "v1", "childIds": ["v1.1", "v1.2"] },
"v1.1": { "id": "v1.1", "parentId": "v1" },
"v1.2": { "id": "v1.2", "parentId": "v1" }}
},
"ids": {
"orders": ["o1", "o2", "o3"],
"products": ["p1", "p2", "p3"],
"views": ["v1", "v1.1", "v1.2"]
}
}
找到正确模型并将原始数据转换为模型的前期工作较多,但您可以节省大量时间,而不必处理嵌套或影响多个数据区域的更新。
由于 redux 不允许改变当前状态并 return 返回,因此很难修改嵌套的子级。尽管非常不鼓励
在 redux 中有这种嵌套结构,而应该将其规范化为 @bsapaka 回答。但是如果你仍然想更新嵌套
对象和 return 整个状态作为一个不可变的状态,immer
应该是你的朋友。 immerJS
在处理不可变 states.Although
在你的案例中安装 immer 和 redux-immer
yarn add immer redux-immer
在您的 reducers.js
文件中,所有减速器已使用 combineReducers
import produce from 'immer';
import { combineReducers } from 'redux-immer';
// Replace your current combineReducers with
combineReducers(produce, { /* Object of all reducers */ });
在你当前的reducer文件中
import product from 'immer';
const findNestedChild = (arr, itemId) => (
arr.reduce((a, item) => {
if (a) return a;
if (item.id === itemId) return item;
if (item['children']) return findItemNested(item['children'], itemId)
}, null)
);
case UPDATE_ORDER_LINES_SUCCESS:
return produce(state, draftState => {
const { row: newChild, row: { id }} = action;
let child = findNestedChild(draftState.views, id);
child = newChild;
});