Home > Mobile >  How to update my useEffect hook when State change happen in a different .js file's component in
How to update my useEffect hook when State change happen in a different .js file's component in

Time:03-10

I am trying to make an API call in useEffect() and want useEffect() to be called everytime a new data is added in the backend. I made a custom Button(AddUserButton.js) which adds a new user in backend. I am importing this button in the file (ManageUsers.js) where I am trying to display all the users. I just wanted to make an useState to keep track everytime an add button is clicked and make useEffect refresh according to it. For Example:

const [counter, setCounter] = useState(0);
...
const handleAdd = () => {
  setCounter(state => (state 1));
};
...
useEffect(() => {
 // fetch data here
 ...
}, [counter]);
...
return(
 <Button onClick = {handleAdd}> Add User </Button>

);

But currently because I have two .js files, I am not sure how to make my logic stated above work in this case

ManageUsers.js

import AddUserButton from "./AddUserButton";
...
export default function ManageShades() {
...
useEffect(() => {
  axios
  .get("/api/v1/users")
  .then(function (response) {
    // After a successful add, store the returned devices
    setUsers(response.data);
    setGetUserFailed(false);
  })
  .catch(function (error) {
    // After a failed add
    console.log(error);
    setGetUserFailed(true);
  });
console.log("Load User useeffect call")

 },[]);
 return (
<div>
  ...
    <Grid item xs={1}>
      
      <AddUserButton title = "Add User" />
      
    </Grid>
  ...
</div>
);
}

AddUserButton.js

export default function AddDeviceButton() {
...

return (
 <div>
  <Button variant="contained" onClick={handleClickOpen}>
    Add a device
  </Button>
 ...
 </div>
 );
} 

CodePudding user response:

A common approach is to pass a callback function to your button component that updates the state of the parent component.

import { useState, useEffect } from "react";

const AddUserButton = ({ onClick }) => {
  return <button onClick={onClick} />;
};

export default function Test() {
  const [updateCount, setUpdateCount] = useState(false);
  const [count, setCount] = useState(0);

  useEffect(() => {
    setCount(count  );
  }, [updateCount]);

  return (
    <div>
      <AddUserButton
        onClick={() => {
          // do something, e.g. send data to your API
          // finally, trigger update
          setUpdateCount(!updateCount);
        }}
      />
    </div>
  );
}

CodePudding user response:

So it seems like you are trying to let a child update it's parent's state, an easy way to do this is to let the parent provide the child a callback, which will update the parent's state when called.

const parent = ()=>{
   const [count, setCount] = useState(0);
   const increCallback = ()=>{setCount(count   1)};

   return (<div> 
      <child callback={increCallback}/>
   </div>);
}

const child = (callback)=>{
   return (<button onClick={callback}/>);
}

CodePudding user response:

If you were to tell the ManageUsers component to fetch from the back-end right after the AddUser event is fired, you will almost certainly not see the latest user in the response.

Why? It will take some time for the new user request to be received by the back-end, a little longer for proper security rules to be passed, a little longer for it to be formatted, sanitized, and placed in the DB, and a little longer for that update to be available for the API to pull from.

What can we do? If you manage the users in state - which it looks like you do, based on the setUsers(response.data) - then you can add the new user directly to the state variable, which will then have the user appear immediately in the UI. Then the new user data is asynchronously added to the back-end in the background.

How can we do it? It's a really simple flow that looks something like this (based roughly on the component structure you have right now)

function ManageUsers() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch('https://api.com')
      .then(res => res.json())
      .then(res => setUsers(res));
      .catch(err => console.error(err));
  }, [setUsers]);

  const handleAdd = ({ name, phone, dob }) => {
    const newUser = {
      name,
      phone,
      dob
    };
    setUsers([...users, newUser]);
  };

  return (
    <div>
      <UserList data={users} />
      <AddUser add={handleAdd} />
    </div>
  );
}

// ...

function AddUser({ add }) {
  const [userForm, setUserForm] = useState({ name: "", phone: "", dob: "" });


  return (
    // controlled form fields
    <button onClick={() => add(userForm)}>Submit</button>
  );
}

// ...

function UserList({ data }) {
  return (
    <>
      {data.map(user =>
        <p>{user.name></p>
      }
    </>
  );
}

Once the user adds a new user with the "Submit" button, it passes the new user to the "add" function which has been passed down as a prop. Then the user is appended to the users array of the ManageUsers component, instantly populating the latest user data in the UserList component. If we wait for a new fetch request to come through, this will add a delay, and the newest user we just added will not likely come back with the response.

  • Related