反应useState不会立即更改

时间:2020-10-04 22:04:58

标签: reactjs react-hooks

  • 有4种状态,分别为贷方,借方,总计和余额,我要执行一些计算。
  • 公式:余额=贷方-借方+总计
  • 我想使用useState来总计余额 的值。
  • 除了 total 的值(在第一次提交表单时不会更新,而是在第二次提交表单时更新)之外,一切正常。
  • useEffect用于代码中,但我不了解如何在首次提交时更新总计
function Code() {
  const [credit, setCredit] = useState(0);
  const [debit, setDebit] = useState(0);
  const [balance, setBalance] = useState(0);
  const [total, setTotal] = useState(0);

  // Hard coded data
  const [records, setRecords] = useState([
    {
      credit: 1200,
      debit: 0,
      total: 1200,
    },
  ]);

  // performing credit & debit calculation and Adding Total into it
  useEffect(() => {
    setBalance(credit - debit + total);
  }, [credit, debit]);

  // Submit Button to save data in >>>records<<<
  const getInfo = (e) => {
    e.preventDefault();

    //to Get Total Value after Submit
    setTotal(balance);
    setRecords([
      ...records,
      {
        credit: credit,
        debit: debit,
        total: total,
      },
    ]);

    // Again Providing Initial Values
    setCredit(0);
    setDebit(0);
    setBalance(0);
  };

  return (
      <div className="App">
        <form>
          <label>Credit</label>
          <input
              type="number"
              value={credit}
              onChange={(e) => setCredit(e.target.value)}
          />
          <br />

          <label>Debit</label>
          <input
              type="number"
              value={debit}
              onChange={(e) => setDebit(e.target.value)}
          />

          <button type="submit" onClick={getInfo}>
            Submit
          </button>
        </form>
        {records.map((record) => (
            <p>
              credit:{record.credit}, debit:{record.debit} Total:{record.total}
            </p>
        ))}
      </div>
  );
}

3 个答案:

答案 0 :(得分:0)

将setState()视为请求而不是立即命令 更新组件。为了获得更好的感知性能,React可能会 延迟它,然后一次通过更新几个组件。反应 不保证状态更改会立即应用。

setState()并不总是立即更新组件。有可能 批处理或将更新推迟到以后。这使得阅读this.state 在调用setState()之后立即发生潜在的陷阱。相反,使用 componentDidUpdate或setState回调(setState(updater, 回调)),保证在更新后都会触发 已应用。如果您需要根据之前的状态设置状态 状态,请阅读下面的updater参数。

因此setTotal(balance)不会立即更新值。

余额应用于更新记录。

更新后的代码段位于下面。

setRecords([
  ...records,
  {
    credit: credit,
    debit: debit,
    total: balance
  },
])

答案 1 :(得分:0)

要点:

setRecords([
  ...records,
  {
    credit,
    debit,
    total: credit - debit + total // for complete confidence
  }
]);

完整代码:

import React, { useState, useEffect } from "react";

function Code() {
  const [credit, setCredit] = useState(0);
  const [debit, setDebit] = useState(0);
  const [balance, setBalance] = useState(0);
  const [total, setTotal] = useState(1200); // Hard coded data too

  // Hard coded data
  const [records, setRecords] = useState([
    {
      credit: 1200,
      debit: 0,
      total: 1200
    }
  ]);

  // performing credit & debit calculation and Adding Total into it
  useEffect(() => {
    setBalance(credit - debit + total);
  }, [credit, debit, total]);

  // Submit Button to save data in >>>records<<<
  const getInfo = (e) => {
    e.preventDefault();

    //to Get Total Value after Submit
    setTotal(balance);
    setRecords([
      ...records,
      {
        credit,
        debit,
        total: credit - debit + total // to enshure
      }
    ]);

    // Again Providing Initial Values
    setCredit(0);
    setDebit(0);
    setBalance(0);
  };

  return (
    <div className="App">
      <form>
        <label>Credit</label>
        <input
          type="number"
          value={credit}
          onChange={(e) => setCredit(e.target.value)}
        />
        <br />

        <label>Debit</label>
        <input
          type="number"
          value={debit}
          onChange={(e) => setDebit(e.target.value)}
        />

        <button type="submit" onClick={getInfo}>
          Submit
        </button>
      </form>
      {records.map((record) => (
        <p>
          credit:{record.credit}, debit:{record.debit} Total:{record.total}
        </p>
      ))}
    </div>
  );
}

export default Code;

答案 2 :(得分:0)

删除余额影响进行计算,余额值可以从贷方和借方中得出。实际上,完全消除平衡会导致大部分重复total的出现,并且说实话,这会使代码变得相当混乱。

创建一个效果钩子,以在更新total数组(即从最后一条记录中“跳过” records)时更新计算出的total。这会“缓存”总计,因此可以成为下一条记录的“更新”源。

useEffect(() => {
  setTotal(records[records.length -1]?.total ?? 0)
}, [records]);

[编辑]

  • Optional Chaining?.)检查对象是否不为空,并继续访问属性。 records[records.length -1]?.total或多或少是records[records.length -1] && records[records.length -1].total的简写。
  • Nullish Coalescing Operator??)与逻辑或(||)类似,它返回右手 左侧操作数为null或未定义时的side操作数。在上面的代码中,如果记录由于某种原因未定义总计,则为total状态提供备用值。
  • records[records.length -1]?.total ?? 0行应与(records[records.length -1] && records[records.length -1].total !== null && records[records.length -1].total !== undefined) ? records[records.length -1].total : 0等效。希望很明显,使用可选链接和无效合并运算符时,可以省去多少冗长的代码。

[/ EDIT]

更新getInfo仅添加新记录,从贷方,借方和总计中得出余额/总计。

const getInfo = (e) => {
  e.preventDefault();

  setRecords((records) => [
    ...records,
    {
      credit,
      debit,
      total: credit - debit + total,
    }
  ]);

  setCredit(0);
  setDebit(0);
};

为了更好地进行测量,请从所有干净的初始状态开始,然后使用onMount效果“加载”记录。上面的第一个效果将处理将总数更新为正确的情况。

const [credit, setCredit] = useState(0);
const [debit, setDebit] = useState(0);
const [total, setTotal] = useState(0);
const [records, setRecords] = useState([]);

useEffect(() => {
  setRecords([
    {
      credit: 1200,
      debit: 0,
      total: 1200
    }
  ]);
}, []);

Edit react-usestate-is-not-changing-immediately