How can I get my state to wait on API data before it fires off?

I have a paginator that determines how many pages to present, based off a data prop that is JSON array’s of data from an API.

  const itemsPerPage = 3;
  const [noOfPages] = React.useState(
    Math.ceil(data[0]?.length / itemsPerPage)
  );

My issue is, how can I create some sort of conditional to wait for the noOfPages state to fire off before receiving the data prop?

Without ?., I’m getting an undefined issue. { data && console.log(data[0].length)} This works just fine, when testing if there is actually data inside the prop. I am not able to re-create this same sort of conditional for my state to wait for the data prop before firing off.

Answer

React always renders current state of your application. This means that all state variables exist as long as component that said values attached to exist. Your goal is to orchestrate said state to render what you want to render – that is called “state management”.

You can go with different solutions here. For example, you can avoid rendering component until data is loaded, or replace that component with some sort of indication. Or you can set your state to some initial value, like 0 and render null until it will become some positive number. This will not work if it is possible that your value will be 0, but this can be mitigated with another state value. Consider this example:

function Pagination() {
  // Here we have one of two possible distinct states: "loading" and "not_loading"
  // It is good to use strings for such states, since later you might want to introduce new state, like "error"
  let [loading_state, set_loading_state] = useState("loading");
  // This is number of pages. It should always exist, but until we are in "not_loading" state we don't actualy care what it would be
  let [number_of_pages, set_number_of_pages] = useState(0);

  useEffect(function () {
    // retrieve data
    let data = ...;
    // set number of pages and loading state
    set_number_of_pages(data[0].length / items_per_page);
    set_loading_state("not_loading");
  }, []);

  if (loading_state === "loading") return  null;
  if (loading_state === "not_loading") return ....;
}

There would be modifications, depending on where you keep and how you retrieve your data. Sometimes it is even better to calculate values “on the fly”, instead of keeping them in state. If there would be some performance heavy computation, you can always use useMemo hook, but this is not your case.

Leave a Reply

Your email address will not be published. Required fields are marked *