如何更新 React 中的嵌套对象状态,用 {} 初始化,然后是我从 api 获取的 json 数据。
为什么此代码不起作用:
import React, { useEffect, useState } from 'react';
import { useQuery } from 'react-query';
const App = () => {
const [testData, setTestData] = useState({});
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch("http://localhost:8080/api/v1/recommendations");
const result = await response.json();
setTestData(result);
} catch (err) {
console.error(`Found error while fetching data: ${err}`);
}
};
fetchData();
}, []);
useEffect(() => {
setTestData(prevState => {
const updatedData = {
...prevState,
recommendation: {
...prevState.recommendation,
rules: prevState.recommendation.rules.map(rule => {
if (rule.scenario_name === "data_rule") {
return {
...rule,
passwhen: {
...rule.passwhen,
STATE: "INDIA"
}
};
}
return rule;
})
}
};
return updatedData;
});
}, []);
useEffect(() => {
console.log("data", testData);
}, [testData]);
return (
<div>
<pre>{JSON.stringify(testData, null, 2)}</pre>
</div>
);
};
export default App;
我正在开发一个 React 应用程序,我需要更新嵌套对象的状态。最初,我的状态设置为空对象 {}。我从应填充此嵌套状态的 API 获取 JSON 数据。 获取数据后,我想更新此嵌套对象中的特定键。但是,我的方法面临问题。在提供的示例中,状态未正确初始化,导致尝试更新嵌套属性时出现错误。 我应该如何使用获取的 JSON 数据正确初始化和更新嵌套对象状态,确保状态更新得到正确且不可变的处理?
API数据
{
"recommendation": {
"rules": [
{
"scenario_name": "duplicate_check",
"scenario_target_query": "SELECT * FROM beat2020.orders_info",
"columns": [
"ORDERNO"
],
"tgt_lvl_key": [
"ORDERNO"
],
"idx": 0
},
{
"scenario_name": "null_check",
"scenario_target_query": "SELECT ORDERNO, QUANTITY_ORDERED, PRICE_EACH, SALES_PRICE, ORDERDATE, STATUS FROM beat2020.orders_info",
"columns": [
"ORDERNO",
"QUANTITY_ORDERED",
"PRICE_EACH",
"SALES_PRICE",
"ORDERDATE",
"STATUS"
],
"idx": 1
},
{
"scenario_name": "data_validation",
"scenario_source_query": "SELECT ORDERNUMBER, QUANTITYORDERED, PRICEEACH, ORDERLINENUMBER, SALES, FORMAT(ORDERDATE, 'MM-DD'), CASE WHEN STATUS IS NULL THEN 1 ELSE 2 END, QTR_ID, MONTH_ID, YEAR_ID, PRODUCTLINE, MSRP, PRODUCTCODE, CUSTOMERNAME, PHONE, ADDRESSLINE1, ADDRESSLINE2, CITY, IF(STATE IS NULL, 'US', STATE), POSTALCODE, COUNTRY, TERRITORY FROM beat2020.orders",
"scenario_target_query": "SELECT ORDERNO, QUANTITY_ORDERED, PRICE_EACH, ORDERLINENO, SALES_PRICE, ORDERDATE, STATUS, QTR_ID, MONTH_ID, YEAR_ID, PRODUCTLINE, MSRP, PRODUCTCODE, CUSTOMERNAME, PHONE, ADDRESSLINE1, ADDRESSLINE2, CITY, STATE, POSTALCODE, COUNTRY, TERRITORY FROM beat2020.orders_info",
"columns": [
"ORDERNUMBER",
"QUANTITYORDERED",
"PRICEEACH",
"ORDERLINENUMBER",
"SALES",
"ORDERDATE",
"STATUS",
"QTR_ID",
"MONTH_ID",
"YEAR_ID",
"PRODUCTLINE",
"MSRP",
"PRODUCTCODE",
"CUSTOMERNAME",
"PHONE",
"ADDRESSLINE1",
"ADDRESSLINE2",
"CITY",
"STATE",
"POSTALCODE",
"COUNTRY",
"TERRITORY"
],
"src_lvl_key": [
"ORDERNUMBER"
],
"tgt_lvl_key": [
"ORDERNO"
],
"idx": 2
},
{
"scenario_name": "data_rule",
"scenario_target_query": "SELECT * FROM beat2020.orders_info",
"passwhen": {
"ORDERDATE": "DATE MM-DD",
"STATUS": "IN 1,2",
"STATE": "IN US"
},
"idx": 3
}
]
}
}
最初,testData 是一个空对象
{}
。当您尝试更新深层嵌套属性(例如recommendation.rules)时,这可能会导致问题,因为它们在初始状态下可能不存在,因为对象是空的。从 API 获取数据后,您可以使用结果正确设置状态。但是,可能存在计时问题,即第二个 useEffect
在获取数据之前运行,从而导致在尝试访问嵌套属性(尚不存在)时出现错误。
您必须确保更新仅在状态正确初始化后发生。
这是一个温和的建议
import React, { useEffect, useState } from 'react';
const App = () => {
const [testData, setTestData] = useState({}); // Initial empty state
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch("http://localhost:8080/api/v1/recommendations");
const result = await response.json();
setTestData(result); // Set state with fetched data
} catch (err) {
console.error(`Found error while fetching data: ${err}`);
}
};
fetchData();
}, []); // Run only once when the component mounts
useEffect(() => {
// Check if the data has been fetched and contains the expected structure
// here you can add your own transformers/validations
if (testData.recommendation && Array.isArray(testData.recommendation.rules)) {
setTestData(prevState => {
return {
...prevState, // spreading
recommendation: {
...prevState.recommendation, // spreading
rules: prevState.recommendation.rules.map(rule => {
if (rule.scenario_name === "data_rule") {
return {
...rule, // spreading
passwhen: {
...rule.passwhen, // spreading
STATE: "INDIA" // Updating the STATE field
}
};
}
return rule;
})
}
};
});
}
}, [testData]); // <= Only run when testData is updated. This part is super important
return (
<div>
<pre>{JSON.stringify(testData, null, 2)}</pre> {/* Display the updated state */}
</div>
);
};
export default App;
更新深度嵌套状态时,需要通过扩展现有对象和数组来仔细处理不变性。强烈推荐这两篇文章: