【问题标题】:Updating Multiple React State within the same event handler在同一事件处理程序中更新多个 React 状态
【发布时间】:2020-06-23 03:47:26
【问题描述】:

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

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;

【问题讨论】:

    标签: reactjs event-handling use-state


    【解决方案1】:

    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。

    【讨论】:

    • 谢谢!所以状态现在正在同步更新,但是现在处于状态的 locationList 数组在组件加载时在其数组中有一个“未定义”对象。我不确定是什么原因造成的。
    • 好的。我在底部添加了完整的代码。我在代码中插入了if (locationList[0] === undefined) { {locationList.shift()} } 作为解决剩余问题的方法。
    【解决方案2】:

    状态的更新是异步行为,因为您正在为 setLocationList 获取未定义的 locationID。 在类组件内部,我们可以像这样使用回调来调用 setState -

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

    但在您的情况下,您使用的是函数组件,因此您必须使用 useEffect 反应钩子来侦听数据的变化,然后更新状态中的其他数据。

    看看这个问题 - How to use `setState` callback on react hooks

    【讨论】:

      猜你喜欢
      • 2017-01-08
      • 1970-01-01
      • 2021-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-02
      • 1970-01-01
      • 2010-12-02
      相关资源
      最近更新 更多