如何根据对象数组中的先前值更新值?

How to update a value based on previous value in an array of objects?

我正在尝试根据另一个 属性 的先前值更新每个当前值。

实际上,我需要用日期来完成任务,但为了简单起见,我将用简单的数字来解释我的问题。

我有

  1. Start,即1
  2. Stop,已经定义
  3. End
  4. Duration,已经定义

我的目标

为了说明,我添加了 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. 如果我们在第一项上,只需从 1 的种子值开始 start
  2. 如果不是,那么我们访问累加器的前一个条目(当前索引减一),并访问其 durationend 属性。将它们总结并用于 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