如何更新react中的嵌套对象状态,用{}初始化,然后是我从api获得的json数据

问题描述 投票:0回答:1

如何更新 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
            }
        ]
    }
}
javascript reactjs redux react-hooks
1个回答
0
投票

最初,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;

更新深度嵌套状态时,需要通过扩展现有对象和数组来仔细处理不变性。强烈推荐这两篇文章:

  1. https://overreacted.io/a-complete-guide-to-useeffect/
  2. https://react.dev/learn/you-might-not-need-an-effect
© www.soinside.com 2019 - 2024. All rights reserved.