I am having a problem with my state managment.
When I click on the select box, nothing happens, when I click on it a 2nd time, it is like it accepts the first click.
This should be showing all the People rows, but it is showing the onChange from before.
Also bonus point if the double useEffects can be modified to be only one function 🙂
import { React, useEffect, useState } from "react";
import TableRow from "../../components/TableRow/TableRow";
import axios from "axios";
export default function SellerList() {
const [rowData, setRowData] = useState({});
const [categoryValue, setCategoryValue] = useState();
const [sdlrValue, setSdlrValue] = useState();
useEffect(() => {
axios
.get("SellerList.json")
.then(function (response) {
setRowData(response["data"]);
})
.catch(function (error) {
console.log(error);
});
}, []);
useEffect(() => {
Object.keys(rowData).map((rowKey, i) => {
rowData[rowKey] = { ...rowData[rowKey], isHidden: false };
return 1;
});
if (categoryValue !== "00") {
Object.keys(rowData).map((rowKey, i) => {
if (categoryValue !== rowData[rowKey]["code"]) {
rowData[rowKey] = { ...rowData[rowKey], isHidden: true };
}
return 1;
});
}
}, [rowData, categoryValue]);
useEffect(() => {
Object.keys(rowData).map((rowKey, i) => {
rowData[rowKey] = { ...rowData[rowKey], isHidden: false };
return 1;
});
if (sdlrValue !== "00") {
Object.keys(rowData).map((rowKey, i) => {
if (sdlrValue !== rowData[rowKey]["sdlrId"]) {
rowData[rowKey] = { ...rowData[rowKey], isHidden: true };
}
return 1;
});
}
}, [rowData, sdlrValue]);
return (
<div>
<h1>Seller Deduplicated Request List</h1>
<table>
<thead>
<tr>
<th></th>
<th>Code</th>
<th>Category</th>
<th>SDRL ID</th>
<th>Data Requested (Name or Label for request)</th>
<th>Request Parameters (Date ranges, etc)</th>
<th>Request Details (Notes to explain request)</th>
<th>Format (File type or format for request)</th>
</tr>
<tr>
<th></th>
<th colSpan={2}>
<select
value={categoryValue}
onChange={(event) => setCategoryValue(event.target.value)}
>
<option value="00">Filter by Category</option>
<option value="02">People</option>
<option value="01">Finance & Accounting</option>
<option value="04">Purchasing</option>
<option value="01">Sales</option>
</select>
</th>
<th>
<select
value={sdlrValue}
onChange={(event) => setSdlrValue(event.target.value)}
>
<option value="00">Filter by SDLR</option>
<option value="01.02">01.02</option>
<option value="02.01">02.01</option>
<option value=" 04.01"> 04.01</option>
<option value="05.01">05.01</option>
</select>
</th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{rowData &&
Object.keys(rowData).map((rowKey, i) => {
return (
<TableRow
key={rowKey}
row={rowData[rowKey]}
setRowData={setRowData}
rowData={rowData}
/>
);
})}
</tbody>
</table>
</div>
);
}
2
Answers
Your code:
is modifying a state variable value without using the "set state function". So React is not aware that the value has changed (to React, modifying the state variable value directly is just changing any other standard variable). So React doesn’t re-render until something else in state changes…at which point the changes you made earlier are finally reflected.
It is a REALLY BAD IDEA to change values of a state variable directly. You almost certainly want to be using the "set state function" to change the value, which queues the component to be re-rendered.
Remember that React only re-renders a component in 2 cases:
Also, it doesn’t make sense to use the
.map()
function if you aren’t going to use its return value. Use.forEach()
instead.Though in this case, it might be a good idea to use the
.map()
and give its return value to the "set state function" as the new state variable value!I just gave a decent (IMO) overview of the difference in the two "set state function" signatures that would be useful here too:
You can use the functional form of setRowData that allows you to access the previous state and ensure that you are working with the most up-to-date data. Additionally, you can combine the two useEffect hooks into a single one to reduce redundancy.