'UseEffect not filling all states

SO this is my code, i'm trying to filter my offers by there users , i have called all my offers and all my user and there states are full but when i try to filter offers by there users the state stay empty but when i hit spacebar on my keyboard the state get full like it's the spacebar is triggering useEffect to fill the state

const [offer, setOffer] = useState([]);
  const [user, setUser] = useState({});
  const[useroffers,setUseroffer]=useState([]);


  const isOffer = async () => {
    const oflg = await GetAllOff();
    setOffer(oflg);
  };


  const isLoggedIn = async () => {
    const userLg = await CurrentUser();
    setUser(userLg.data.user);
  };

  const isUseroffer = async()=>{
   setUseroffer(offer.filter((el)=>el.createdbyId === user._id));
  };
 
 
  useEffect( () => {
    isOffer();
    isLoggedIn();
    isUseroffer();
  }, []);
  console.log(offer);
  console.log(user)
  console.log(useroffers); 

So useEffect is filling the offers and user States but not filling the useroffers state intil i click on the spacebar



Solution 1:[1]

useroffers is dependent on both user and offer but you are trying to set it in the same render cycle as those two. Updated state values aren't available until the render cycle after they are set, so setUseroffers doesn't have access to the values it needs to update properly. To solve this you can declare a second useEffect which is dependent on user and offer so that as those values update so does your filtered array.

  const [offer, setOffer] = useState([]);
  const [user, setUser] = useState({});
  const [useroffers, setUseroffer] = useState([]);

  const isOffer = async () => {
    const oflg = await GetAllOff();
    setOffer(oflg);
  };

  const isLoggedIn = async () => {
    const userLg = await CurrentUser();
    setUser(userLg.data.user);
  };

  useEffect(() => {
    isOffer();
    isLoggedIn();
  }, []);

  useEffect(() => {
    setUseroffer(offer.filter((el) => el.createdbyId === user._id));
  }, [user, offer]);

codesandbox


Alternatively you can do it all in a single useEffect by awaiting the offer and user values and using them directly to set all three states once they are available. (This will result in only a single rerender rather than the possible four in the previous example)

  const [offer, setOffer] = useState([]);
  const [user, setUser] = useState({});
  const [useroffers, setUseroffer] = useState([]);

  useEffect(() => {
    const login = async () => {
      const userLg = await CurrentUser();
      const ofLg = await GetAllOff();

      setUser(userLg.data.user);
      setOffer(ofLg);
      setUseroffer(
        ofLg.filter((el) => el.createdbyId === userLg.data.user._id)
      );
    };

    login();
  }, []);

codesandbox

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1