How can I call a useEffect only once after everything loads from redux useSelector hooks?

Viewed 171

I'm new to React and am wondering if it's possible to use a useEffect that will run only once after all the Redux data has been loaded.

I'm trying to disable the "Buyer" and "Seller" dropdowns if there has been a specified Seller AND Buyer. However if there is only a Buyer or only a Seller while the other is still not selected (still has default value of -1), I want to be able to use the dropdown to select the buyer/sellers without the dropdowns immediately disabling after a buyer and seller has been selected, hence why I'm trying to only get it to run once. Instead, the dropdowns should be disabled the next time the entire page is reloaded/refreshed.

The issue that I'm running into is that if I use a useEffect with an empty array of dependencies so that it will only run once, it seems like it's running before the data from the redux hooks is actually loaded. Is there a way for me to run it after everything has been loaded from redux or any other way for me to do this? Relevant Code is below.

  const [selectedBuyerNumber, setBuyerNumber] = useState(-1);
  const [selectedSellerNumber, setSellerNumber] = useState(-1);
  const [disabled, setDisabled] = useState(false);

  const dispatch = useDispatch();
  const buyerNumber = useSelector(selectors.buyerNumberState);
  const sellerNumber = useSelector(selectors.sellerNumberState);
  const loaded = useSelector(selectors.loadingState);


  useEffect(() => {
    loaded && setBuyerNumber(buyerNumber ?? -1);
  }, [buyerNumber, loaded]);

  useEffect(() => {
    dispatch(setBuyerNumber(selectedBuyerNumber));
  }, [dispatch, selectedBuyerNumber]);

  useEffect(() => {
    loaded && setSelectedSellerNumber(sellerNumber ?? -1);
  }, [sellerNumber, loaded]);

  useEffect(() => {
    dispatch(setSellerNumber(selectedSellerNumber));
  }, [dispatch, selectedSellerNumber]);

  useEffect(() => { 
      setDisabled(selectedBuyerNumber !== -1 && selectedSellerNumber !== 1);
    }
  }, []);   //dependencies are empty because I only want this to run once and be disabled if both Buyer and Seller have previously been selected


return (
<FormGroup controlId='buyer'>
  <ControlLabel>Buyer:</ControlLabel>
       <FormControl
          componentClass='select'
          onChange={(e: any) => setBuyerNumber(e.target.value)}
          value={selectedBuyerNumber}
          disabled={disabled}>               
</FormGroup>
            
<FormGroup controlId='seller'>
   <ControlLabel>Seller:</ControlLabel>
      <FormControl
           componentClass='select'
           onChange={(e: any) => setSellerNumber(e.target.value)}
           value={selectedSellerNumber}
           disabled={disabled}>
</FormGroup>






1 Answers

These are the useEffect's that I would use:

useEffect(() => {
    if (loaded) {   
        setBuyerNumber(buyerNumber ?? -1);
        setSellerNumber(sellerNumber ?? -1);
        setDisabled((buyerNumber && sellerNumber) ? true : false)
    }
}, [loaded]);

useEffect(() => {
  dispatch(setBuyerNumber(selectedBuyerNumber));
}, [dispatch, selectedBuyerNumber]);

useEffect(() => {
  dispatch(setSellerNumber(selectedSellerNumber));
}, [dispatch, selectedSellerNumber]);

With the first one you will set if the dropdows are going to be disabled or not. And since loaded state only changes once (when loaded ...) that useEffect will execute only once.

Related