#reactjs #react-hooks #use-effect #use-state #asynccallback
#reactjs #реагирующие хуки #использование-эффект #use-state #asynccallback
Вопрос:
Я довольно новичок в ReactJS и, возможно, либо слишком сложный, либо не планировал его должным образом.
Я столкнулся с проблемой при использовании перехвата useState для отслеживания свойств в моем проекте.
итак, итак
value
берется из текстового поля ввода в качестве текста ввода, из-за использованияreact-hook-form
type
затем проверяется, чтобы увидеть, равно ли оно «Доходу» или «расходу»- Если
type == "income"
тогда просто установитеvalue
usingsetValue
без каких-либо изменений, иначе, еслиtype == "expense"
тогда*=-1
и установитеvalue
usingsetValue
parseInt()
используется сsetValue
, чтобы убедиться, что значение сохраняется как числоsetRecords
вызывается для добавления соответствующей информации вrecord
массив объектов.
итак, как вы можете видеть из 5 шагов выше, useState hook setValue
и setRecords
вызывается один за другим, проблема, с которой я сталкиваюсь на данный момент, заключается в том, что при первоначальном запуске приложения value
вместо добавления будет добавляться.
насколько я понимаю, поскольку перехват useState является асинхронным и не возвращает результат немедленно, поэтому к моменту setRecords
вызова value
все еще имеет тип text вместо number
Я некоторое время искал в Интернете, но не смог найти хорошего способа решить эту проблему, не используя useEffect hook, я пытался использовать useEffect hook, но мне не удалось заставить его работать, пользователю разрешено вводить то же value
самое, и приложение все равно должно добавлятьзначение в record
массив объектов.
в конце концов, я решил создать новое свойство currentValue
и установить его в форме отправки, потому что это не состояние и оно будет обновляться немедленно, ему не придется ждать setValue
обновления value
состояния.
Есть ли лучший способ обойти эту проблему? или обходной путь в порядке?
import React, { useEffect, useContext } from "react";
import RecordList from "./RecordList";
import { useForm } from "react-hook-form";
import { BudgetPlannerContext } from "../context/BudgetPlannerContext";
const BudgetPlanner = () => {
const { register, handleSubmit, errors } = useForm();
const [
records,
setRecords,
total,
setTotal,
type,
setType,
value,
setValue,
description,
setDescription,
] = useContext(BudgetPlannerContext);
let currentValue = 0;
useEffect(() => {
setTotal(() =>
records.reduce((acc, curr) => {
return acc curr.value;
}, 0)
);
}, [records, setTotal]);
const onFormSubmit = (data) => {
if ((type === "Income") amp; (data.value !== 0)) {
currentValue = parseInt(data.value);
setValue(parseInt(data.value));
} else if ((type === "Expense") amp; (data.value !== 0)) {
currentValue = parseInt((data.value *= -1));
setValue(parseInt((data.value *= -1)));
} else {
return null;
}
setDescription(data.description);
processValue(type, currentValue);
};
const processValue = (type, currentValue) => {
updateRecord(type, currentValue);
//setValue(0);
//setDescription("");
//console.log(records);
};
const updateRecord = (type, currentValue) => {
setRecords((oldRecord) => [
...oldRecord,
{
type: type,
value: currentValue,
description: description,
id: Math.random() * 1000,
},
]);
};
return (
<div className="ui segment">
<div className="search-bar ui segment">
<form className="ui form" onSubmit={handleSubmit(onFormSubmit)}>
<div className="field">
<select
onChange={(e) => setType(e.target.value)}
name="todos"
ref={register}
className="filter-todo"
>
<option value="" defaultValue="defaultValue">
---
</option>
<option value="Income">Income</option>
<option value="Expense">Expense</option>
</select>
<input
name="description"
type="text"
placeholder="Description"
ref={register}
/>
<input
name="value"
type="number"
placeholder="Value"
ref={register}
/>
</div>
<div>Total: {total}</div>
<button type="submit">Submit</button>
</form>
</div>
<RecordList records={records} setRecords={setRecords} />
</div>
);
};
export default BudgetPlanner;
Ответ №1:
На вашем месте я бы просто передал новое значение в качестве параметра другим вызываемым вами функциям:
const onFormSubmit = (data) => {
if (data.value === 0 || (type !== 'Income' amp;amp; type !== 'Expense')) {
return;
}
const newValue = parseInt(data.value) * (type === 'Income' ? 1 : -1);
setValue(newValue);
setDescription(data.description);
processValue(type, newValue);
};
Нет необходимости в дополнительной внешней переменной.
Другой вариант — использовать useEffect
(или, предпочтительно, useLayoutEffect
) и вызывать processValue
при value
изменении:
const onFormSubmit = (data) => {
if (data.value === 0 || (type !== 'Income' amp;amp; type !== 'Expense')) {
return;
}
const newValue = parseInt(data.value) * (type === 'Income' ? 1 : -1);
setValue(newValue);
setDescription(data.description);
};
useLayoutEffect(() => {
if (value) {
processValue(type);
}
}, [value]);
и processValue
используйте внешнюю value
переменную с отслеживанием состояния.
Комментарии:
1. Спасибо за быстрый ответ, я принял ваше первое предложение по
onFormSubmit
функции и внес изменения в свой код, теперь он выглядит намного лучше.