Nini Michaels
Nini Michaels

Reputation: 340

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);

Upvotes: 5

Views: 1606

Answers (5)

Eduardo Junior
Eduardo Junior

Reputation: 350

That's a functional component, or a stateless component. It has not it's own state. So if you change the value of the numbers variable, will not change the state of the component. If you really want to use a functional component, you should write the logic of fetching the url and updating the state in a parent stateful component and pass the numbers variable as a prop to the stateless component.

Otherwise if you don't need to use a functional component. Change it to a class component, and put the numbers variable as a state parameter and change it through the setState() method, and everything should work as expected.

I recommend this article.

Tip: A functional component can have state now through Hooks.

Upvotes: 1

Laura Nutt
Laura Nutt

Reputation: 313

In frontend creation, rendering is the most important procedure a programmer has to handle. The render) (method in React is the only method needed in a class component and is responsible for defining the view to be rendered in the browser window. There are many subtleties about how this approach works, combined with the clever way that React operates around its virtual DOM concept, and knowing them would greatly benefit any aspiring React developer. For a demonstration of discussed habits, I will refer to this codepen. render() 101 Render) (is, first of all, not user-callable. It is part of the life cycle of the React component and is called by React at different phases of the app, normally when the React component is first instantiated, or when the component state is newly changed. Render does not take any arguments, and returns the JSX.Element that contains the current component's view hierarchy. This hierarchy of views will be later converted to HTML and shown in the browser window. Within the lifecycle, these are the scenarios where render is called:

After the React component is first instantiated, following the constructor() call. After an update to the component’s props After a setState() call I would recommend this article- https://en.wikipedia.org/wiki/React_(web_framework) to understand the fundamentals, first.

Upvotes: 1

Gaurav Tiwari
Gaurav Tiwari

Reputation: 771

The above code snippet would help you to understand the proper usage of dumb(aka Stateless) and smart(Stateful) component.

Start thinking of it using react life cycles, to make it even more clearer

In the above snippet the render() has already ran with the initial value

let numbers = [0];

and since the changes are not carried out in STATE or PROPS the rerendering is not happening and you are not getting the intended result.

Solution -

  • Make the functional component a class component ie make it a smart component or use hooks (useState) to make it a smart component.
  • Use prop drilling i.e calculate the value in the parent component and pass it down to the child component using props

Take this as an opportunity to prepare your mindset towards "THINKING in REACT"

More on Stateful vs Stateless

Upvotes: 2

Tholle
Tholle

Reputation: 112777

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>

Upvotes: 2

sjahan
sjahan

Reputation: 5940

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.

Upvotes: 2

Related Questions