I'm pretty new to reactJS, and may have either over complicated things or didn't plan it properly.
I have encountered an issue with using the useState hook to keep track of properties in my project.
ok, so here goes
valueis taken from an input text box as type text, due to usingreact-hook-formtypeis then checked, to see if it's equal to "Income" or "Expense"- If
type == "income"then just set thevalueusingsetValuewithout any changes, else iftype == "expense"then*=-1and setvalueusingsetValue parseInt()is used with thesetValueto make sure the value is saved as a numbersetRecordsis called to add the relevant information intorecordarray of objects.
so as you can see from the 5 steps above, useState hook setValue and setRecords is getting called one after the other, the issue I'm having at the moment is that on the initial run of the app, the value would append instead of adding.
from what I understand is that because the useState hook is asynchronous and does not return a result immediately, so by the time the setRecords is called, value still of type text instead of number
I have been searching online for a while but was unable to find a good way to resolve this issue, without using useEffect hook, I have tried to use useEffect hook, but I didn't manage to get it to work, the user is allowed to enter the same value and the app should still append the value into the record array of objects.
in the end, I decided to create a new property currentValue and set it on form submit, because this is not a state and will update immediately, it won't have to wait for setValue to update the value state.
Is there a better way to work around this issue? or is the workaround ok?
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") & (data.value !== 0)) {
currentValue = parseInt(data.value);
setValue(parseInt(data.value));
} else if ((type === "Expense") & (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;