1

These are my states using hooks:

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"
     });

I have a bunch of fields with onChange handlers and an onClick handler that needs to update 3 states in order. First, LocationAddress has to become the state of the location property within the location state. Second, the location state has to be updated with a unique ID, and then that unique ID is inserted into the array in the locationList state. Finally, the entire array from locationList state is added to the locations property of adminProfile state. These are all in one component.

const handleClickLocation = () => {

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

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

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

The first time the click handler is triggered, it sets only the first state in the handler and sends "undefined" into the second state. When the click handler is clicked a second time, it then behaves normally. I want all the states to update simultaneously. I've tried forceUpdate(), but couldn't figure out the syntax. I've tried using ReactDOM.unstable_batchedUpdates but it still behaved the same.

How can I get this to work? I want to keep this within one component. Is that possible?

Here is the entire code updated with the useEffect hook:

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;

2 Answers2

0

Updating of the state is asynchronous behavior, because of that you are getting locationID undefined for setLocationList. Inside class component, we can use a callback to setState call like this -

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

But in your case, you are using function component so you have to use useEffect react hook to listen for changes in your data and then update other data in the state.

Take a look at this question - How to use `setState` callback on react hooks

Sagar Darekar
  • 982
  • 9
  • 14
0

setState is asynchronous, it means that when it is called, its state won't update at the same time, it takes some time to perform its action.

You can make use of useEffect to do that.

useEffect will perform an action only when the specified state (inside brackets) changes

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

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

Ps: You can have multiple useEffects in your code.

  • Thanks! So the states are now updating synchronously, but now the locationList Array that is being held in state, has an "undefined" object in its array when the component loads. I'm not sure what's causing that. – user1760020 Jun 23 '20 at 06:06
  • Okay. I added the full code at the bottom. I inserted `if (locationList[0] === undefined) { {locationList.shift()} }` into the code as a workaround to the remaining issue. – user1760020 Jun 23 '20 at 20:48