0

The React doc states that the intermediate state will not be shown to the user, but why in this example it does show "loading...." (the intermediate state in this case)?

You may call setState() immediately in componentDidMount(). It will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though the render() will be called twice in this case, the user won’t see the intermediate state.

class MyComponent extends React.Component {
        constructor(props) {
            
          super(props);
          this.state = {
            error: null,
            isLoaded: false,
            items: []
          };
        }
    
        componentDidMount() {
    
          fetch("https://jsonplaceholder.typicode.com/posts")
            .then(res => res.json())
            .then(
              (result) => {
                this.setState({
                  isLoaded: true,
                  items: result
                });
              },
              // Note: it's important to handle errors here
              // instead of a catch() block so that we don't swallow
              // exceptions from actual bugs in components.
              (error) => {
                this.setState({
                  isLoaded: true,
                  error
                });
              }
            )
        }
        render() {
    
          const { error, isLoaded, items } = this.state;
          if (error) {
    
            return <div>Error: {error.message}</div>;
          } else if (!isLoaded) {
    
            return <div>Loading...</div>;
          } else {
    
            return (
              <ul>
                {items.map(item => (
                  <li key={item.id}>
                    {item.userId} - {item.title}
                  </li>
                ))}
              </ul>
            );
          }
        }
    }

When I do not use AJAX calls the intermediate state is not seen ("loading...) for example:

class MyComponent extends React.Component {
        constructor(props) {
          super(props);
          this.state = {
            error: null,
            isLoaded: false,
            items: []
          };
        }
        componentDidMount() {
                                  
          this.setState({
            isLoaded: true,
            items: [
              { "id": 1, "name": "Apples",  "price": "$2" },
              { "id": 2, "name": "Peaches", "price": "$5" }
            ] 
          });
              
        }
        render() {
          const { error, isLoaded, items } = this.state;
          if (error) {
            return <div>Error: {error.message}</div>;
          } else if (!isLoaded) {
            return <div>Loading...</div>;
          } else {
            return (
              <ul>
                {items.map(item => (
                  <li key={item.id}>
                    {item.id} - {item.name}
                  </li>
                ))}
              </ul>
            );
          }
        }
      }

1 Answers1

2

Because in the first example, you're not calling setState immediately in componentDidMount().

You're calling it from a function the asynchronous fetch() invocation (eventually) calls.

AKX
  • 152,115
  • 15
  • 115
  • 172
  • Thanks @AKX, I read this here on stackoverflow "I believe if you set the state in componentDidMount synchronously, the new state will be the only one shown (or at least the switch would happen so fast after rendering it would be impossible to detect). If you're trying to set it asynchronously, such as using results from a fetch, then you would see the initial state until the async call is completed". So, is that statement I read correct? –  Sep 13 '22 at 12:48
  • 3
    Yes, and that's what the documentation you've quoted says too (that a `setState` occurring in `componentDidMount` will happen before anything is rendered onto the screen). – AKX Sep 13 '22 at 12:48
  • ok, so, because of waiting for asynchronous code (when using fetch), React has no choice but to show the intermediate state, right? –  Sep 13 '22 at 12:54
  • 3
    Somewhat. React is not waiting for anything there – you're just firing off an asynchronous request that eventually may call a function that calls `setState`. – AKX Sep 13 '22 at 12:54
  • Great @AKX, excellent answer, this last comment of yours opened up the picture even more for me, done, marked as best answer. –  Sep 13 '22 at 12:57