ncesar
ncesar

Reputation: 1792

State wont update with useEffect using Axios

I'm building a simple component that receives a word and send it backwards, then, it gets the new word, sends to a dictionary API and shows the result. I have created a isLoading state and error State. When i get a response different from 200, error should be true. But in my code, this is not happening. So, when i get a response different from 200, the code tries to render {dictionaryData.entry.sense[1].def} and crashes.

import React, { useState, useEffect, useRef } from "react";
import axios from "axios";
import "./App.css";

function App() {
  const [anagram, setAnagram] = useState("");
  const [anagramResult, setAnagramResult] = useState("");
  const [dictionaryData, setDictionaryData] = useState({});
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(false);

  const isFirstRun = useRef(true);
  useEffect(() => {
    if (isFirstRun.current) {
      isFirstRun.current = false; //i'm using useRef to not run this code on the first run
      return;
    }

    const fetchData = async () => {
      const result = await axios(
        `http://dicionario-aberto.net/search-json/${anagramResult}`
      );
      if (result.status === 200) {
        setDictionaryData(result.data);
        console.log(result.data);
        setIsLoading(false);
        setError(false);
      } else {
        setError(true);
        setIsLoading(true);
      }
    };
    fetchData();
  }, [anagramResult]);

  const reverseWord = word => {
    setAnagramResult([...word].reverse().join``);
  };

  return (
    <div className="App">
      <input
        type="text"
        name="anagram"
        onChange={e => setAnagram(e.target.value)}
        value={anagram}
      />
      <button onClick={() => reverseWord(anagram)}>Check Anagram</button>
      <p>result: {anagramResult}</p>
      {isLoading ? null : (
        <div>
          <p>Definições: {dictionaryData.entry.sense[1].def}</p>
          <p>{dictionaryData.entry.sense[2].def}</p>
          <p>{dictionaryData.entry.sense[3].def}</p>
        </div>
      )}
      {error ? <p>Houve um erro na pesquisa ou a palavra não existe.</p> : null}
    </div>
  );
}

export default App;

Sorry for any mistake, i'm just trying to understand hooks.

Upvotes: 2

Views: 552

Answers (1)

SuleymanSah
SuleymanSah

Reputation: 17858

I made some changes to your code.

I set isLoading default value to false, that makes more sense.

I wrapped "await axios" with try catch to handle all kind of errors.

Can you check please?

import React, { useState, useEffect, useRef } from "react";
import axios from "axios";
import "./App.css";

function App() {
  const [anagram, setAnagram] = useState("");
  const [anagramResult, setAnagramResult] = useState("");
  const [dictionaryData, setDictionaryData] = useState({});
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(false);

  const isFirstRun = useRef(true);
  useEffect(() => {
    if (isFirstRun.current) {
      isFirstRun.current = false; //i'm using useRef to not run this code on the first run
      return;
    }

    const fetchData = async () => {
      setIsLoading(true);

      try {
        const result = await axios.get(
          `http://dicionario-aberto.net/search-json/${anagramResult}`
        );
        setIsLoading(false);
        if (result.status === 200) {
          setDictionaryData(result.data);
          setError(false);
        } else {
          setDictionaryData({});
          setError(true);
        }
      } catch (error) {
        setDictionaryData({});
        setError(true);
        setIsLoading(false);
      }
    };
    fetchData();
  }, [anagramResult]);

  const reverseWord = word => {
    setAnagramResult([...word].reverse().join``);
  };

  return (
    <div className="App">
      <input
        type="text"
        name="anagram"
        onChange={e => setAnagram(e.target.value)}
        value={anagram}
      />
      <button onClick={() => reverseWord(anagram)}>Check Anagram</button>
      <p>result: {anagramResult}</p>
      {isLoading && <p>Loading...</p>}
      {!isLoading && dictionaryData.entry && (
        <div>
          <p>Definições: {dictionaryData.entry.sense[1].def}</p>
          <p>{dictionaryData.entry.sense[2].def}</p>
          <p>{dictionaryData.entry.sense[3].def}</p>
        </div>
      )}
      {error ? <p>Houve um erro na pesquisa ou a palavra não existe.</p> : null}
    </div>
  );
}

export default App;

Upvotes: 1

Related Questions