Home > Mobile >  React component doesn't re-render after setState
React component doesn't re-render after setState

Time:09-19

i have state vacations, i set it after fetch within useEffect, i have button approve that will change data in vacation state and i want to re-render component after that happens within function handleApprove , so i made up virtual state componentShouldUpdate with initial value of false and passed it as a dependency for useEffect, and when function handleApprove gets triggered, i setState to the opposite of its value !componentShouldUpdate, but the component only re-render when i click 2 times, why is that happening and why it works fine when i setState componentShouldUpdate from a child component ?


function VacationsComponent() {
  const [vacations, setVacations] = useState([{}]);
  const [componentShouldUpdate, setComponentShouldUpdate] = useState(false);

  useEffect(() => {
    const getVacations = async () => {
      const response = await fetch("http://localhost:8000/get-vacations");
      const data = await response.json();
      setVacations(data);
    };

    getVacations();
  }, [componentShouldUpdate]);

  const handleApprove = async (e, vactionId) => {
    (await e.target.value) === "approve"
      ? fetch(`http://localhost:8000/approve-vacation/${vactionId}`, {
          method: "POST",
        })
      : fetch(`http://localhost:8000/reject-vacation/${vactionId}`, {
          method: "POST",
        });

    setComponentShouldUpdate(!componentShouldUpdate);
  };

    <button onClick={(e) => handleApprove(e, item._id)}>
      APPROVE
    </button>

}

CodePudding user response:

This is most probably caused because useState hook operates asynchronously. Read more here.

You can update your code to use only one state like this

function VacationsComponent() {
  const [vacations, setVacations] = useState([{}]);

  const getVacations = async () => {
    const response = await fetch("http://localhost:8000/get-vacations");
    const data = await response.json();
    setVacations(data);
  };
  useEffect(() => {
    getVacations();
  }, []);

  const handleApprove = async (e, vactionId) => {
    const slug =
      e.target.value === "approve" ? "approve-vacation" : "reject-vaction";
    await fetch(`http://localhost:8000/${slug}/${vactionId}`, {
      method: "POST",
    });

    getVacations();
  };

  <button onClick={(e) => handleApprove(e, item._id)}>APPROVE</button>;
}

CodePudding user response:

put the setComponentShouldUpdate(!componentShouldUpdate) inside a thenable like this, and remove the async/await construct.

Also what was the intended purpose for setting state, I don't see the boolean being used anywhere. Usually when setting state you want the DOM to be updated somewhere, and especially with a boolean its great for toggling elements on the screen.

 const handleApprove = (e, vactionId) => {
    e.target.value === "approve"
      ? fetch(`http://localhost:8000/approve-vacation/${vactionId}`, {
          method: "POST",
        }).then(()=>{ 
           // does this go here if it is approved or when it s rejected 
           setComponentShouldUpdate(!componentShouldUpdate); 
        })
      : fetch(`http://localhost:8000/reject-vacation/${vactionId}`, {
          method: "POST",
        }).then(()=>{ setComponentShouldUpdate(!componentShouldUpdate); });

  
  };
  • Related