'React re-render problem with same data but different object of API
I am hitting a backend API which contains array of objects. I am storing the API data in a state called reportsTabData. This state contains array of objects and one object who's key is reports contains array of objects called options and each options contains array of objects called fields. I am setting the fields array of objects in my state called optionsTabData and I am creating a UI based on optionsTabData.
Example:
[
..some objects,
{
key: "report",
default: "incoming"
options: [
{
type: "incoming",
fields: [
{
colspan: "1"
key: "CLAppSchedulerRepDependentSelectors"
label: "Extension(s) Selection"
type: "CLAppSchedulerRepDependentSelectors"
}
]
},
{
type: "outgoing",
fields: [
{
colspan: "1"
key: "CLAppSchedulerRepDependentSelectors"
label: "Extension(s) Selection"
type: "CLAppSchedulerRepDependentSelectors"
}
]
}
]
}
]
The code works fine and UI is generated, but as you see, there are some reports who's fields contain same objects. The problem is the state update is not re-rendering for such use-case else it works fine.
Below is the code:
const [loader, setLoader] = useState(false);
const [optionsTabData, setOptionsTabData] = useState([]);
useEffect(() => {
callForApi()
},[])
const callForApi = async () => {
setLoader(true);
let response = await getRequest("api-url");
if (response.status == 200 && response.status <= 300) {
let adapter = response.data.schema;
setAdapterData(adapter);
setReportsTabData(adapter.report.fields);
setDistributionTabData(adapter.distribution.fields);
let data = [];
for (const ele of adapter.report.fields) {
if (ele.key === "report") {
for (const item of ele.options) {
if (item.type === ele.default) {
data = [...item.fields];
break;
}
}
break;
}
}
setOptionsTabData(data);
} else {
toastErrorMessagePopUp(response.data.detail);
}
setLoader(false);
};
const handleDropdownChange = (key, value) => {
if (key === "report") {
const schema = [...reportsTabData];
let report = schema.find((ele) => ele.key === "report");
let newOptions = []
for (const ele of report.options) {
if (ele.type === value) {
newOptions=[...ele.fields];
break;
}
}
setOptionsTabData([...newOptions])
}
}
How do I solve this? Apparently, doing something like await setOptionsTabData([]) before setOptionsTabData([...newOptions]) solves it but I think using await is a bad idea and also the value reflecting after a click in dropdown is sluggish and slow.
Solution 1:[1]
You can "force" the re-render by using a combination of JSON.stringify and JSON.parse
setOptionsTabData(JSON.parse(JSON.stringify(newOptions)))
Solution 2:[2]
It looks like it should be working. You are passing new array to setOptionsTabData which should trigger a rerender.
Using await is not a solution - functions returned by useState are synchronous and that should not make a difference. What's actually happening is you are resetting your optionsData state to an empty array and then setting it to the desired data.
Is there more code you can show? Maybe you have a useEffect somewhere that updates your UI with unfulfilled dependencies?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Apostolos |
| Solution 2 | Andrey Mikus |
