Reputation: 340
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
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
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
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 -
Take this as an opportunity to prepare your mindset towards "THINKING in REACT"
Upvotes: 2
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
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