Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding async React rendering

I'm new to learning React, and I'm wondering why the following code doesn't work as expected. I thought that it would display The numbers: 0123 but it only displays 0. I've also used the same approach with class based component, and using hooks and I still get the same result. What am I not understanding with react rendering using async code?

import React from "react";
import ReactDOM from "react-dom";

function App() {
  let numbers = [0];

  fetch("some.url")
    .then(res => res.json())
    .then(list => {
      for (let n of list) {
        numbers.push(n);
      }
    });

  return <div className="App">The numbers: {numbers}</div>;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
like image 504
Nini Michaels Avatar asked Mar 13 '19 13:03

Nini Michaels


People also ask

What is async rendering in React?

This means that while the component Shows is waiting for some asynchronous operation, such as fetching shows from TVMaze's API, React will render <p>loading... </p> to the DOM instead. The Shows component is then rendered only after the promises and APIs are resolved.

How does async work in React?

React Async is a promise-based library that offers a declarative API to make API calls. It provides a React component and a Hook for declarative promise resolution and data fetching. React Async is compatible with almost all the data fetching libraries and APIs, including Fetch API, Axios, and GraphQL.

Is React suspense still experimental?

With the Release of React 18, the Suspense feature has been further developed and enhanced. It fits many use cases and now it is compatible with SSR . It still can't be used for data fetching though. This feature is still in experimental mode and might make it to a further release.


2 Answers

Your code prints 0 because it is the value of the variable number at render time.

You use the following code:

fetch("some.url")
    .then(res => res.json())
    .then(list => {
      for (let n of list) {
        numbers.push(n);
      }
    });

to get a new value asynchronously, but it won't have any effect: the component is already rendered.

If you want to refresh it, you must put your variable number in the state and use setState() to pass the new value.

If you want to keep with function components, you should use the brand new hooks feature, which should give you the equivalent of setState.

like image 168
sjahan Avatar answered Oct 19 '22 06:10

sjahan


You can use the useState hook to create a piece of state that is an array, and get the list of numbers with the useEffect hook and update the numbers when that request has finished.

Example

const { useState, useEffect } = React;

function getNumbers() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve([1, 2, 3, 4, 5]);
    }, 1000);
  });
}

function App() {
  const [numbers, setNumbers] = useState([0]);

  useEffect(() => {
    getNumbers().then(list => {
      setNumbers(numbers => [...numbers, ...list]);
    });
  }, []);

  return <div className="App">The numbers: {numbers.join(", ")}</div>;
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>
like image 2
Tholle Avatar answered Oct 19 '22 08:10

Tholle