在同一事件处理程序中更新多个 React 状态

Updating Multiple React State within the same event handler

这些是我使用钩子的状态:

const [adminProfile, setProfile] = useState({
        locations: [],
        });

    const [location, setLocation] = useState({

        locationName: "",
        location: {},
        locationPhone: "",
        locationEmail: "",
        staff: [],
        multipleKitchens: false,
        kitchens: [],
    });

    const [locationList, setLocationList] = useState([]);

    const [locationAddress, setAddress] = useState({
            streetAddress: "",
            streetAddress2: "",
            city: "",
            state: "",
            zip: "",
            country: "USA"
     });

我有一堆带有 onChange 处理程序的字段和一个需要按顺序更新 3 个状态的 onClick 处理程序。首先,LocationAddress 必须成为位置状态中位置 属性 的状态。其次,必须使用唯一 ID 更新位置状态,然后将该唯一 ID 插入到 locationList 状态的数组中。最后,locationList 状态的整个数组被添加到 adminProfile 状态的位置 属性。这些都在一个组件中。

const handleClickLocation = () => {

        setLocation(prevValue => ({
            ...prevValue,
            locationID: uuidv4(),
            location: locationAddress
        }));

        setLocationList(prevValue => [...prevValue, location.locationID]);

        setProfile(prevValue => ({
            ...prevValue,
            locations: locationList
        }))

第一次触发点击处理程序时,它只在处理程序中设置第一个状态,并将“未定义”发送到第二个状态。当单击处理程序被第二次单击时,它会正常运行。我希望所有状态同时更新。我试过 forceUpdate(),但无法弄清楚语法。我试过使用 ReactDOM.unstable_batchedUpdates 但它仍然表现相同。

我怎样才能让它工作?我想将其保留在一个组件中。这可能吗?

这是使用 useEffect 挂钩更新的完整代码:

import React, {useState, useEffect} from "react";
import axios from "axios";
const { v4: uuidv4 } = require('uuid');

const CompanyProfileInfo = (props) => {

    const todayDate = () => {
        let today = new Date();
        let day = today.getDate();
        let month = today.getMonth() + 1;
        let year = today.getFullYear();
        if (day < 10) day = '0' + day;
        if(month < 10) month = '0' + month;
        return (month + "/" + day + "/" + year);

    }

    const [adminProfile, setProfile] = useState({
        companyID: props.companyInfo.companyID,
        firstName: "",
        lastName: "",
        phonePrimary: "",
        phoneSecondary: "",
        emailSecondary: "",
        streetAddress: "",
        streetAddress2: "",
        city: "",
        state: "",
        zip: "",
        country: "USA",
        multipleLocations: false,
        locations: [],
        membershipLevel: "Basic",
        joinedDate: todayDate(),
        });

    const [location, setLocation] = useState({
        
        locationName: "",
        locationPhone: "",
        locationEmail: "",
        staff: [],
        multipleKitchens: false,
        kitchens: [],
    });

    

    const [locationAddress, setAddress] = useState({
            streetAddress: "",
            streetAddress2: "",
            city: "",
            state: "",
            zip: "",
            country: "USA"
     });

     const [locationList, setLocationList] = useState([]);

     useEffect(() => {
        setLocationList(prevValue => [...prevValue, location.locationID]);

     }, [location.locationID]);

     useEffect(() => {
         if (locationList[0] === undefined) {
             {locationList.shift()}
         }
        setProfile(prevValue => ({
            ...prevValue,
            locations: locationList
        })
        
        )
     }, [locationList])

    const handleChange = (event) => {
        const {name, value} = event.target;
        setProfile(prevValue => ({
            ...prevValue,
            [name]: value
        }))
    }

    const handleChangeLocations = (event) => {
        const {name, value} = event.target;
        setLocation(prevValue => ({
            ...prevValue,
            [name]: value
        }));
    };

    const handleChangeLocations1 = (event) => {
        const {name, value} = event.target;
        setAddress(prevValue => ({
            ...prevValue,
            [name]: value
            
        }));
    };

 

    const handleClickLocation = () => {

        setLocation(prevValue => ({
            ...prevValue,
            locationID: uuidv4(),
            location: locationAddress,
            
        }));

    };

    const handleClick = () => {


        axios.post('http://localhost:3001/profileinfo', adminProfile)
          .then(res => {
              props.supportFunctions.setUpLocations(res);
          })
          .catch(function (error) {
              console.log(error);
          })
    }

    return (
        <div>


    
        </div>
    )
}

export default CompanyProfileInfo;

状态更新是异步行为,因此您将获得 setLocationList 未定义的 locationID。 在 class 组件中,我们可以像这样使用回调来调用 setState -

this.setState({ data: newData }, () => { console.log("This will get printed after setState") })

但是在你的情况下,你使用的是函数组件,所以你必须使用 useEffect react hook 来监听你的数据变化,然后更新状态中的其他数据。

看看这个问题 -

setState是asynchronous,意思是当它被调用时,它的状态不会同时更新,它需要一些时间来执行它的动作.

您可以使用 useEffect 来做到这一点。

useEffect 将仅在指定状态(括号内)更改

时执行操作
useEffect(() => {
   setLocation({
       ...location,
       location: locationAddress,
       locationID: uuidv4()
   })
}, [locationAddress]) //When locationAddress changes, setLocation

useEffect(() => {
   setLocationList([
          ...locationList,
          location.locationID
       ])
}, [location]) //When location changes, insert Id 

Ps:您的代码中可以有多个 useEffects。