Wait for a parent state to change in an onClick Event React using hooks

Viewed 130

The problem I am facing is the following.

I have a React stateless dropdown component which has exposed an onClick method.

When this onClick method is triggered I change the dropdown state which is again passed to the same dropdown component.

The dropdown component is as follows:

<DynamicDropdown
    dropdown={dropdownData}
    state={dropdownState}
    onToggleClick={onDropdownToggleClick}
    onDismissDropdown={onDismissDropdown}
/>

Currently the onDropdownToggleClick method is as follows:

const [dropdownState, setDropdownState] = useState<DropdownState>();
const onDropdownToggleClick = async (s: DropdownState) => {
  if (s === 'closed') {
    setDropdownState('fetching');
    const requests = await EnvironmentsAPI.getEnvironmentActiveRequests(
      environmentId
    );
    setActiveRequests(requests);
    setDropdownState('open');
  } else {
    setDropdownState('closed');
  }
};

Now I have a requirement that I have one state fetching coming from the redux store in my React component. This fetches some data every 15seconds and is a boolean value.

Now the requirement is that when the dropdown is toggled (onDropdownToggleClick) and fetching is true, I have to set my dropdownState as 'fetching' and wait for it to become false. When it becomes false then only I have to execute the statement

const requests = await EnvironmentsAPI.getEnvironmentActiveRequests(
  environmentId
);

Now the problem is that fetching is handled by redux and it does not gives a promise which I can await.

I tried doing 2 things:

1 -

const onDropdownToggleClick = async (s: DropdownState) => {
  setEnvironmentToggled(true);
  if (fetching) {
    setDropdownState('fetching');
  } else {
    if (s === 'closed') {
      setDropdownState('fetching');
      const requests = await EnvironmentsAPI.getEnvironmentActiveRequests(
        environmentId
      );
      setActiveRequests(requests);
      setDropdownState('open');
    } else {
      setDropdownState('closed');
    }
  }
};

and then there is a useEffect in which I open the dropdown like

useEffect(() => {
  if (!fetching) {
    setDropdownState('open');
  }
},[]);

But the problem here is fetching is being polled every 15 seconds and most of the time it is false. Every 15 seconds it is changed to true for 1 second at max. So most of the times my dropdown becomes 'open' even if the API to fetch environments is not complete.

2 - I try to manually create a promise somehow which will resolve when fetching changes. This promise will only be created when dropdown is toggled.

const [fetchingResolve, setFetchingResolve] = useState<
  (value?: unknown) => void
>();
useEffect(() => {
  if (!fetching && fetchingResolve) {
    fetchingResolve();
  }
}, [fetching, fetchingResolve]);
const onDropdownToggleClick = async (s: DropdownState) => {
  if (s === 'closed') {
    setDropdownState('fetching');
    const fetchingPromise = new Promise(resolve => {
      setFetchingResolve(resolve);
    });
    await fetchingPromise;
    const requests = await EnvironmentsAPI.getEnvironmentActiveRequests(
      environmentId
    );
    setActiveRequests(requests);
    setDropdownState('open');
  } else {
    setDropdownState('closed');
  }
};

Now this promise is getting resolved immediately. I tried keeping this promise in useRef.

const fetchingResolve = useRef<(value?: unknown) => void>();
useEffect(() => {
  console.log(fetchingResolve.current);
  if (!fetching && fetchingResolve.current) {
    fetchingResolve.current();
  }
}, [fetching, fetchingResolve.current]);
const onDropdownToggleClick = async (s: DropdownState) => {
  if (s === 'closed') {
    setDropdownState('fetching');
    const fetchingPromise = new Promise(resolve => {
      fetchingResolve.current = resolve;
    });
    await fetchingPromise;
    const requests = await EnvironmentsAPI.getEnvironmentActiveRequests(
      environmentId
    );
    setActiveRequests(requests);
    setDropdownState('open');
  } else {
    setDropdownState('closed');
  }
};

This worked partially. The problem with this was if the fetchingResolve.current is undefined initally then it will wait for the next cycle of fetching(15 seconds) before updating.

Any leads or another approach will be very helpful. Thanks.

Let me know if I am not able to explain my problem.

0 Answers
Related