Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

234
Visualizações
Does order of state variable matters in React?

When I execute the code below gives an error "Cannot read properties of null (reading 'login')", because it reaches the return statement at the end, which it should not as I already have checks for the boolean before return.

import React, { useState, useEffect } from 'react';
const url = 'https://api.github.com/users/QuincyLarsn';
const MultipleReturns = () => {
  const [isLoading, setIsLoading] = useState(true);
  const [isError, setIsError] = useState(false);
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetch(url)
      .then(data => {
        if (data.status >= 200 && data.status <= 299)
          return data.json();
        else {
          console.log("here");
          setIsLoading(false);
          setIsError(true);
          console.log("here 2");
        }
      })
      .then(result => {
        setIsLoading(false);
        setUser(result);
      })
      .catch(error => console.log(error))
  }, []);

  console.log(isError);
  if (isLoading)
    return <h2>Loading...</h2>
  if (isError) {
    return <h2>Error...</h2>
  }

  return <h2>{user.login}</h2>

};

export default MultipleReturns;

In the above code if setIsError(true) is placed before setIsLoading(false) in useEffect, then everything works fine but not vice versa, similarly if the url is correct then too things work fine if setUser(result) is placed before setIsLoading(false) and not vice versa. I am not able to figure out why that is the case.

about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

React is not batching state updates from fetch(). It is batched in case of event listeners. This is an async fetch call.

In this sandbox console, you can see that there is a render in between your state updates - setIsLoading(false) and setIsError(true).

So for one render cycle : isLoading is false and isError is also false. That will lead to the error condition.

You can use unstable_batchedUpdates to enforce batching.

import { useEffect, useState } from "react";
import { unstable_batchedUpdates } from "react-dom";
import "./styles.css";

const url = "https://api.github.com/users/QuincyLarsn";
const App = () => {
  const [isLoading, setIsLoading] = useState(true);
  const [isError, setIsError] = useState(false);
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetch(url)
      .then((data) => {
        if (data.status >= 200 && data.status <= 299) return data.json();
        else {
          console.log("here");
          unstable_batchedUpdates(() => {
            setIsLoading(false);
            setIsError(true);
          });
          console.log("here 2");
        }
      })
      .then((result) => {
        setIsLoading(false);
        setUser(result);
      })
      .catch((error) => {
        console.log(error);
      });
  }, []);

  console.log("isError", isError);
  if (isLoading) return <h2>Loading...</h2>;
  if (isError) return <h2>Error...</h2>;

  return <h2>{user.login}</h2>;
};

export default App;

Corrected Sandbox Link

about 4 years ago · Juan Pablo Isaza Relatório

0

In a such case, order does matter.

While React may batch updates in this case, it's not guaranteed and even if it does, it may call the render function with the in-between state.

So, when isLoading is set to false, but user is not yet set, you get an error.

You can fix this by setting the user first, and then making isLoading false.

But the real solution would be to eliminate the unnecessary state variables: isLoading is true while isError is false and user is null, and false otherwise.

So, you can do it like this:

should not as I already have checks for the boolean before return.

import React, { useState, useEffect } from 'react';
const url = 'https://api.github.com/users/QuincyLarsn';
const MultipleReturns = () => {
  const [isError, setIsError] = useState(false);
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetch(url)
      .then(data => {
        if (data.status >= 200 && data.status <= 299)
          return data.json();
        else {
          console.log("here");
          setIsError(true);
          console.log("here 2");
        }
      })
      .then(result => {
        setUser(result);
      })
      .catch(error => console.log(error))
  }, []);

  console.log(isError);
  if (isError) {
    return <h2>Error...</h2>
  }
  if (user !== null) {
    return <h2>{user.login}</h2>
  }
  return <h2>Loading...</h2>
};

export default MultipleReturns;
about 4 years ago · Juan Pablo Isaza Relatório

0

After you set isLoading as false, the code moves to the last return statement as the error is still false at the moment. So first setting the error blocks the code at the second return statement.

Similarly if you set isLoading as false then set the user, the code will move to the last return statement before the user is set and it will show error. Setting the user and then making isLoading as false shows the user perfectly.

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda