skip to Main Content

I am writing a simple react page where user details can be fetched from one API and pass it to another API multiple times with some modification.


export default function User() {
  const [userid, setUserId] = useState("");
  const [userData, setUserData] = useState({});

const synchToLocation=(loc)=>{
    setUserData((userData)=>({...userData,id:1234,location:loc}));
    const requestOptions = {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(userData)
    };
    fetch("http://localhost:8080/api/v1/synch" , requestOptions);    
  }

const handleSynch = () => {
    synchToLocation(1);  
    synchToLocation(2);
    synchToLocation(3);
  };

  const fecthUser = (event) => {
    event.preventDefault();
    console.log(userid);
    fetch("http://localhost:8080/api/v1/synch/emp?id=" + userid).then((result) =>
    result.json().then((e) => {          setUserData({...userData,id:e.id,firstName:e.firstName,lastName:e.lastName,role:e.role,location:e.location,status:e.status});
      })
    );
  };


  return (
     <Container>
            <TextField
                id="id"
                label="user id"
                value={userid}
                onChange={(e) => setUserId(e.target.value)}
                fullWidth
                required
              ></TextField>
              <Button
                variant="contained"
                color="secondary"
                type="submit"
                onClick={fecthUser}
              >
                Search
                <SearchOutlined />
              </Button>

         <Box>
            <Button variant="contained" color="secondary" onClick={handleSynch}>
              Synch
            </Button>
          </Box>
    </Container>
);
}

I have one text field and two button (search and synch).
Expectation:

  • if user click search button, fetch userdata for user input id and set to state.
  • if user click Synch button, user data should update with specific location and call api with updated location.

Actual Result:

  • User data fetch on search as expected.
  • Api calling with old data or some time calling with last updated data.

Please suggest me the better way to achieve this.

2

Answers


  1. Hooks and useEffect() will allow you to update local state and re-render based on this updated state.

    see: https://reactjs.org/docs/hooks-effect.html

    const SimpleComp = (userName, fetchUserAPI, fetchLocalParams) => {
    
    const [userData, setUserData] = useState(null);
    const [localParams, setLocalParams] = useState(null);
    
    useEffect(() => {
        setUserData( fetchUserAPI(userName) );
    }, []);
    
    useEffect(() => {
        setLocalParams( fetchLocalParams(userData) );
      }, [userData]);
    
    return (
        <>UserData: {userData}  localParams: {localParams}</>
        );
    };
    
    export default SimpleComp;
    

    The initial-state for both Hooks is null. The first useEffect() with empty watch parameters ([]) will be called on-load. The second useEffect() is watching the Hook: userData. When userData changes; this useEffect will be called with the updated state. The first calls the fetchUserData on-load. This updates userData to the return from the API call. This sets User Data with the new value. The second useEffect will then be called because the userData-Hook has changed state. That useEffect calls the fetchLocalParametersAPI and sets this Hook’s value to the returned data.

    All of these changes in Hook state triggers re-render after all of the useEffects() have been evaluated. At that time; all of the Hook variables should be up-to-date and rendering the localParameters based on the userData.

    If you need to use the sync button approach; then create an onClick that sets a new userName Hook from a text-input and update userName onClick(). Just create another useEffect that watches userName and calls fetchUserDataAPI with the new username. This will update the userData Hook which will then call fetchLocalParams when userData changes.

    Login or Signup to reply.
  2. The problem is here. Because the setState work asynchronously so after setUserData, the request body sometimes use the old userData over the new userData that u have set earlier.

    const synchToLocation=(loc)=>{
        setUserData((userData)=>({...userData,id:1234,location:loc}));
        const requestOptions = {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(userData)
        };
        fetch("http://localhost:8080/api/v1/synch" , requestOptions);    
      }
    

    you should change the property body of object to

    body:JSON.stringify({...userData,id:1234,location:loc})
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search