#reactjs #react-hooks
#reactjs #реагирующие крючки
Вопрос:
- Есть 4 состояния: кредит, дебет, итого и баланс, и я хочу выполнить некоторые вычисления.
- Формула: баланс = кредит — дебет итого .
- Я хочу сохранить значение баланса в общем использовании
useState
. - Все работает нормально, за исключением значения total, которое не обновляется при первой отправке формы, оно обновляется при второй отправке формы.
useEffect
используется в коде, но я не понимаю, как обновить total при самой первой отправке.
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 amp; 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>
);
}
Комментарии:
1. Эффект
setBalance
in возникает после всех обновлений состояния в очередиgetInfo
. Совсем не ясно, что вы хотите, чтобы код действительно выполнял, иначе я бы попытался это исправить. Похоже, вы хотите перенести итоговую сумму из предыдущей записи в качестве отправной точки для вычисления итоговой суммы следующей записи (т. Е. Что-то вроде total = previousTotal (credit — debit)).2. Начальная сумма должна быть инициализирована до 1200 с
useState(1200)
помощью вместоuseState(0)
3. @DrewReese да, я хочу точно то же самое
4. все работает нормально, но я только хочу обновить total (useState), чтобы работать с ним в будущем. @DrewReese
Ответ №1:
Удалите эффект баланса для вычисления значение баланса может быть получено из кредитов и дебетов. Фактически, полностью удалите баланс, он, по-видимому, в основном дублируется total
и, честно говоря, делает код довольно запутанным.
Создайте перехват эффекта для обновления вычисляемого total
при records
обновлении массива, т.Е. «снимайте» total
с последней записи. Это «кэширует» итоговое значение, поэтому оно может быть общим для «обновления» для следующей записи.
useEffect(() => {
setTotal(records[records.length -1]?.total ?? 0)
}, [records]);
[ПРАВИТЬ / ПРАВИТЬ код]
- Необязательная функция Chaining (
?.
) проверяет, что объект не имеет нулевого значения, и продолжает доступ к свойствам.records[records.length -1]?.total
более или менее сокращенно дляrecords[records.length -1] amp;amp; records[records.length -1].total
. - Нулевой оператор объединения (
??
) аналогичен логическому ИЛИ (||
), он возвращает операнд правой стороны, когда операнд левой стороны равен нулю или не определен. В приведенном выше коде это обеспечивает резервное значение дляtotal
состояния, если по какой-либо причине запись имеет неопределенное значение. - В целом строка
records[records.length -1]?.total ?? 0
должна быть эквивалентна(records[records.length -1] amp;amp; records[records.length -1].total !== null amp;amp; records[records.length -1].total !== undefined) ? records[records.length -1].total : 0
. Надеюсь, очевидно, насколько менее подробным может быть код при использовании необязательной цепочки и нулевого оператора объединения.
[/ ПРАВИТЬ / ПРАВИТЬ код]
Обновление 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
}
]);
}, []);
Комментарии:
1. вы объяснили мне эту строку кода
useEffect(() => { setTotal(records[records.length -1]?.total ?? 0) }, [records]);
? и ?? как эти операторы работают в этом коде2. @USAMA Абсолютно, исправил мой ответ небольшим объяснением по двум.
Ответ №2:
Думайте о setState() как о запросе, а не о немедленной команде для обновления компонента. Для лучшей воспринимаемой производительности React может задержать его, а затем обновить несколько компонентов за один проход. React не гарантирует, что изменения состояния будут применены немедленно.
setState() не всегда немедленно обновляет компонент. Это может привести к пакетной обработке или отложению обновления на более поздний срок. Это делает чтение this.state сразу после вызова setState() потенциальной ловушкой. Вместо этого используйте componentDidUpdate или обратный вызов setState (setState(updater, обратный вызов)), любой из которых гарантированно сработает после применения обновления. Если вам нужно установить состояние на основе предыдущего состояния, прочитайте о аргументе программы обновления ниже.
Поэтому setTotal(balance)
общее значение не будет обновляться немедленно.
баланс должен использоваться для обновления записей.
Обновленный фрагмент кода приведен чуть ниже.
setRecords([
...records,
{
credit: credit,
debit: debit,
total: balance
},
])
Ответ №3:
основной момент в :
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 amp; 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;