Home > database >  Force react to wait for state change (fetching data)
Force react to wait for state change (fetching data)

Time:09-04

In my link shortening app I was doing everything in one function and now I would like to split it into smaller functions but there is a problem when it comes to fetching. When I fetch data from api, js is waiting for it to be fetched but next functions are being processed before data is saved in a state. It results in component being rendered without needed data because render starts before state is ready. How can I fix it?

const checkLink = () => {
    if (!nextLink) {
      setErrorMsg("Please add link");
      return false;
    } else if (!nextLink.match(linkRegex)) {
      setErrorMsg("That's not a link");
      return false;
    } else {
      return true;
    }
  };
  const fetchShortenedLink = async () => {
    setIsLoading(true);
    const response = await fetch(
      `https://api.shrtco.de/v2/shorten?url=${nextLink}`
    );
    if (!response.ok) {
      setErrorMsg(`An error has occured: ${response.status}`);
      setIsLoading(false);
    } else {
      const data = await response.json();
      await setFetchedLink(data.result.short_link)
      setIsLoading(false);
    }
  };
  const shortenLink = async () => {
    checkLink();
    await fetchShortenedLink();
    setLinkArr((prev) => [
      ...prev,
      {
        id: prev.length === 0 ? 1 : prev[prev.length - 1].id   1,
        long: nextLink,
        short: fetchedLink,
      },
    ]);
    setNextLink("");
    scrollToLink();
  };

CodePudding user response:

The "react" way of doing this would be to use useEffect() and add the state change you want to wait for in the dependency array. Using your own example:

const shortenLink = async () => {
  checkLink();
  await fetchShortenedLink();
  setLinkArr(...); 
  setNextLink("");
};

useEffect(
  () => { scrollToLink() }, // Whatever you want to do after the state changes
  [linkArray, nextLink]     // Add the state you changed in this dependency array
}

CodePudding user response:

Setting State in React is async and you can't await on it. But you could achieve this by different methods.

You could possibly use a React Ref to store the state of the state variable. Then update the state variable with the react ref. This will render a page refresh, and then use the React Ref in the async function.

const stateRef = React.useRef().current
const [state,setState] = useState(stateRef);

async function some() {
  stateRef = { some: 'value' }
  setState(stateRef) // Triggers re-render
  
  await some2();
}

async function some2() {
  await someHTTPFunctionCall(stateRef.some)
  stateRef = null;
  setState(stateRef) // Triggers re-render
}
  • Related