Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

State returning empty array

I'm trying to access state from useState hook but it is giving me the initial state even after I have modified it.

const quotesURL = "https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json";


function QuoteGenerator() {
  const [quotes, setQuotes] = useState([]);
  const [currentQuote, setCurrentQuote] = useState({ quote: "", author: "" });

  useEffect(() => {
    axios(quotesURL)
      .then(result => {
        console.log(result);
        setQuotes(result.data);
      })
      .then(() => {

        console.log(quotes);
      });
    }, []);

console.log(quotes) is returning empty array instead of array of objects

like image 881
Jibin Thomas Avatar asked Jun 27 '19 06:06

Jibin Thomas


People also ask

How do you create an empty array in useState?

We can also create a state based on an empty array: import { useState } from "react"; const [products, setProducts] = useState([]); Now, let's see how to add/push a new value to the array state. Since the state is immutable, we can't simply push a new value value to the array like we do normally in plain JavaScript.

What does an empty dependency array do?

An empty array simply means that there are no dependencies that will trigger the callback within it. Our code inside the callback will run once when the component gets registered, and that is it. The useEffect hook acts like componentDidMount method if an empty array is passed as the dependency array.

What will happen if you leave an empty array of dependencies?

Empty dependency array So what happens when the dependency array is empty? It simply means that the hook will only trigger once when the component is first rendered. So for example, for useEffect it means the callback will run once at the beginning of the lifecycle of the component and never again.

How do you create an array in state?

Instead, every time you want to update an array, you'll want to pass a new array to your state setting function. To do that, you can create a new array from the original array in your state by calling its non-mutating methods like filter() and map() . Then you can set your state to the resulting new array.


1 Answers

Here's how you should do it:

const quotesURL = "https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json";


function QuoteGenerator() {
  const [quotes, setQuotes] = useState([]);
  const [currentQuote, setCurrentQuote] = useState({ quote: "", author: "" });

  useEffect(() => {         // THIS WILL RUN ONLY AFTER YOUR 1ST RENDER
    axios(quotesURL)
      .then(result => {
        console.log(result);
        setQuotes(result.data);  // HERE YOU SET quotes AND IT WILL TRIGGER A NEW RENDER
      })
    }, []);                 // BECAUSE YOU'VE SET IT WITH '[]'

  useEffect(() => {         // THIS WILL RUN WHEN THERE'S A CHANGE IN 'quotes'
     if (quotes.length) {
       setSomeOtherState();   // YOU CAN USE IT TO SET SOME OTHER STATE
     }
  },[quotes]);

}

How this code works:

  • 1st render: You just the the initial states. useEffects are not run yet.
  • After 1st render: Both effects will run (in that order). The first one will fire the axios request. The second one will do nothing, because quotes has no length yet.
  • Axios request completes: the thenclause will run and setQuotes will be called to set the new quotes value. This will trigger a re-render.
  • 2nd render: Now the quotes state has beens updated with the new value.
  • After 2nd render: Only the second useEffect will run, because it's "listening" for changes in the quotes variable that just changes. Then you can use it to set some state like you said.
like image 160
cbdeveloper Avatar answered Nov 09 '22 08:11

cbdeveloper