如何根据对象数组中的先前值更新值?
How to update a value based on previous value in an array of objects?
我正在尝试根据另一个 属性 的先前值更新每个当前值。
实际上,我需要用日期来完成任务,但为了简单起见,我将用简单的数字来解释我的问题。
我有
Start
,即1
Stop
,已经定义
End
Duration
,已经定义
我的目标
Start
= 上一个索引的 Duration
+ 上一个索引的 End
End
= Start
+ Stop
当前值
为了说明,我添加了 table 的屏幕截图,它应该是这样的:
当前视图:
下面的代码和sandbox link
import React from "react";
import { AgGridReact } from "ag-grid-react";
import "./styles.css";
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-alpine.css";
function App() {
let start = 1;
const [gridApi, setGridApi] = React.useState(null);
const [gridColumnApi, setGridColumnApi] = React.useState(null);
const onGridReady = (params) => {
setGridApi(params.api);
setGridColumnApi(params.columnApi);
};
const defaultColDef = {
flex: 1,
editable: true
};
const columnDefs = [
{
headerName: "Name",
field: "name"
},
{
headerName: "start",
field: "updatedStart"
},
{ headerName: "stop", field: "stop" },
{
headerName: "end",
field: "end"
},
{
headerName: "duration",
field: "duration",
colId: "duration"
}
];
const rowData = React.useMemo(
() => [
{
name: "John",
stop: 10,
duration: 5
},
{
name: "David",
stop: 15,
duration: 8
},
{
name: "Dan",
stop: 20,
duration: 6
}
],
[]
);
const rowDataWithStart = React.useMemo(() => {
return (
rowData &&
rowData.map((row, i) => ({
...row,
start: start
}))
);
}, [start, rowData]);
const rowDataWitEnd = React.useMemo(() => {
return (
rowDataWithStart &&
rowDataWithStart.map((row, i) => ({
...row,
end: row.start + row.stop
}))
);
}, [rowDataWithStart]);
//this function(rowDataWitUpdatedStart) should get the previous value of end and duration and get the total
const rowDataWitUpdatedStart = React.useMemo(() => {
return (
rowDataWitEnd &&
rowDataWitEnd.map((row, i) => ({
...row,
updatedStart: row.end + row.duration
}))
);
}, [rowDataWitEnd]);
return (
<div className="App">
<h1 align="center">React-App</h1>
<div className="ag-theme-alpine">
<AgGridReact
columnDefs={columnDefs}
rowData={rowDataWitUpdatedStart}
defaultColDef={defaultColDef}
domLayout={"autoHeight"}
onGridReady={onGridReady}
></AgGridReact>
</div>
</div>
);
}
export default App;
我尝试使用我使用的库 valueGetter
来完成任务:AG Grid
,但似乎不是最好的方法。看看我的 previous question
任何帮助将不胜感激
您无需对数据进行 step-wise 转换,只需使用 Array.prototype.reduce
一次性完成您想要的所有操作。我们在这里使用 Array.prototype.reduce
的方式与您使用 Array.prototype.map
的方式几乎相似(我们将对象 as-is 推入一个新数组,因此没有转换数据),但优点是我们可以访问第三个参数中的当前索引,这允许我们访问累加器中前一项的值。
Array.prototype.map
在这种情况下不起作用,因为在每次迭代中它将无法访问前一项中更新的 start
,除非您有 hack-ish 方式将其存储在函数之外。
根据您的逻辑,如果您希望 start
是前一项的持续时间 + 结尾,我们可以使用此逻辑:
curCopy.start = idx === 0 ? 1 : (acc[idx - 1].duration + acc[idx - 1].end);
...基本上说:
- 如果我们在第一项上,只需从
1
的种子值开始 start
- 如果不是,那么我们访问累加器的前一个条目(当前索引减一),并访问其
duration
和 end
属性。将它们总结并用于 start
在新的返回对象记忆数组中使用此逻辑:
const updatedRowData = React.useMemo(() => {
const updated = rowData.reduce((acc, cur, idx) => {
const curCopy = {...cur};
const previous = acc[idx - 1];
curCopy.start = idx === 0 ? 1 : (previous.duration + previous.end);
curCopy.end = curCopy.start + curCopy.stop;
acc.push(curCopy);
return acc;
}, []);
return updated;
}, [rowData]);
然后在您的模板中,只需使用 rowData={updatedRowData}
。
它应该会生成您预期的结果:
我已经分叉了你的沙箱来创建一个 proof-of-concept 例子:
我会遍历所有元素,保留已处理条目(结果)的列表,然后将开始和结束添加到项目中。
(当然,第一个是异常的,因为您需要将开始硬编码为 1)
const result = [];
for (let i = 0; i < rowData.length; i++) {
const thisValue = rowData[i];
if (i === 0) {
const firstValue = { ...thisValue, start: 1, end: 1 + thisValue.stop };
result.push(firstValue);
} else {
const previousValue = result[i - 1];
const start = previousValue.end + previousValue.duration;
const end = start + thisValue.stop;
result.push({ ...thisValue, start, end });
}
}
return result;
}, [rowData]);
你可以在我的fork上查看这个sandbox
我正在尝试根据另一个 属性 的先前值更新每个当前值。
实际上,我需要用日期来完成任务,但为了简单起见,我将用简单的数字来解释我的问题。
我有
Start
,即1
Stop
,已经定义End
Duration
,已经定义
我的目标
Start
= 上一个索引的Duration
+ 上一个索引的End
End
=Start
+Stop
当前值
为了说明,我添加了 table 的屏幕截图,它应该是这样的:
当前视图:
下面的代码和sandbox link
import React from "react";
import { AgGridReact } from "ag-grid-react";
import "./styles.css";
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-alpine.css";
function App() {
let start = 1;
const [gridApi, setGridApi] = React.useState(null);
const [gridColumnApi, setGridColumnApi] = React.useState(null);
const onGridReady = (params) => {
setGridApi(params.api);
setGridColumnApi(params.columnApi);
};
const defaultColDef = {
flex: 1,
editable: true
};
const columnDefs = [
{
headerName: "Name",
field: "name"
},
{
headerName: "start",
field: "updatedStart"
},
{ headerName: "stop", field: "stop" },
{
headerName: "end",
field: "end"
},
{
headerName: "duration",
field: "duration",
colId: "duration"
}
];
const rowData = React.useMemo(
() => [
{
name: "John",
stop: 10,
duration: 5
},
{
name: "David",
stop: 15,
duration: 8
},
{
name: "Dan",
stop: 20,
duration: 6
}
],
[]
);
const rowDataWithStart = React.useMemo(() => {
return (
rowData &&
rowData.map((row, i) => ({
...row,
start: start
}))
);
}, [start, rowData]);
const rowDataWitEnd = React.useMemo(() => {
return (
rowDataWithStart &&
rowDataWithStart.map((row, i) => ({
...row,
end: row.start + row.stop
}))
);
}, [rowDataWithStart]);
//this function(rowDataWitUpdatedStart) should get the previous value of end and duration and get the total
const rowDataWitUpdatedStart = React.useMemo(() => {
return (
rowDataWitEnd &&
rowDataWitEnd.map((row, i) => ({
...row,
updatedStart: row.end + row.duration
}))
);
}, [rowDataWitEnd]);
return (
<div className="App">
<h1 align="center">React-App</h1>
<div className="ag-theme-alpine">
<AgGridReact
columnDefs={columnDefs}
rowData={rowDataWitUpdatedStart}
defaultColDef={defaultColDef}
domLayout={"autoHeight"}
onGridReady={onGridReady}
></AgGridReact>
</div>
</div>
);
}
export default App;
我尝试使用我使用的库 valueGetter
来完成任务:AG Grid
,但似乎不是最好的方法。看看我的 previous question
任何帮助将不胜感激
您无需对数据进行 step-wise 转换,只需使用 Array.prototype.reduce
一次性完成您想要的所有操作。我们在这里使用 Array.prototype.reduce
的方式与您使用 Array.prototype.map
的方式几乎相似(我们将对象 as-is 推入一个新数组,因此没有转换数据),但优点是我们可以访问第三个参数中的当前索引,这允许我们访问累加器中前一项的值。
Array.prototype.map
在这种情况下不起作用,因为在每次迭代中它将无法访问前一项中更新的 start
,除非您有 hack-ish 方式将其存储在函数之外。
根据您的逻辑,如果您希望 start
是前一项的持续时间 + 结尾,我们可以使用此逻辑:
curCopy.start = idx === 0 ? 1 : (acc[idx - 1].duration + acc[idx - 1].end);
...基本上说:
- 如果我们在第一项上,只需从
1
的种子值开始start
- 如果不是,那么我们访问累加器的前一个条目(当前索引减一),并访问其
duration
和end
属性。将它们总结并用于start
在新的返回对象记忆数组中使用此逻辑:
const updatedRowData = React.useMemo(() => {
const updated = rowData.reduce((acc, cur, idx) => {
const curCopy = {...cur};
const previous = acc[idx - 1];
curCopy.start = idx === 0 ? 1 : (previous.duration + previous.end);
curCopy.end = curCopy.start + curCopy.stop;
acc.push(curCopy);
return acc;
}, []);
return updated;
}, [rowData]);
然后在您的模板中,只需使用 rowData={updatedRowData}
。
它应该会生成您预期的结果:
我已经分叉了你的沙箱来创建一个 proof-of-concept 例子:
我会遍历所有元素,保留已处理条目(结果)的列表,然后将开始和结束添加到项目中。
(当然,第一个是异常的,因为您需要将开始硬编码为 1)
const result = [];
for (let i = 0; i < rowData.length; i++) {
const thisValue = rowData[i];
if (i === 0) {
const firstValue = { ...thisValue, start: 1, end: 1 + thisValue.stop };
result.push(firstValue);
} else {
const previousValue = result[i - 1];
const start = previousValue.end + previousValue.duration;
const end = start + thisValue.stop;
result.push({ ...thisValue, start, end });
}
}
return result;
}, [rowData]);
你可以在我的fork上查看这个sandbox