简体   繁体   中英

React hooks useeffect

I am having an issue with my app in that it re renders a new joke twice when I click the new button function. Here is my code:

    import React, { useState, useEffect } from "react";
import { Typography, Button } from "@material-ui/core";

import Navigation from "../Navigation";
export default function RandomJoke() {
  const [isLoaded, setLoaded] = useState(false);
  const [jokeData, setJokeData] = useState({});
  const [loadNewJoke, setLoadNewJoke] = useState(false);

  function useFetch() {
    async function fetchMyAPI() {
      let response = await fetch("https://icanhazdadjoke.com/slack");
      response = await response.json();
      setJokeData(response);
      setLoaded(true);
    }

    useEffect(() => {
      fetchMyAPI();
      if (loadNewJoke) setLoadNewJoke(false);
    }, [loadNewJoke]);
  }
  useFetch();

  function reloadJoke() {
    setLoaded(false);
    setLoadNewJoke(true);
  }

  return (
    <>
      <Navigation mainpage="RandomJoke" />

      <Typography variant="h6">Random Dad Joke</Typography>
      {isLoaded && <div>{jokeData.attachments[0].text}</div>}
      {!isLoaded && <div>loading...</div>}
      {isLoaded && (
        <Button variant="contained" onClick={() => reloadJoke()}>
          New one
        </Button>
      )}
    </>
  );
}

I tried adding a newjoke state hook but still couldn't work it out. Thank you

That useEffect fires whenever the value of loadNewJoke changes, right? Not just when loadNewJoke is set to true. Look closely at the calls made after a button press, and how many times setLoadNewJoke is called.

Try to move:

if (loadNewJoke) setLoadNewJoke(false);

In your fetchMyApi function. I'm guessing when you hit the button, you trigger the effect cuz u change you deps value in this case to true. Then before effect is over you change it again to false which will triggeer re-run on your effect. But why you dont just trigger fetchApi in your callback on button click, this way you can remove 1 state [loadNewJoke, setLoadNewJoke], will also remove the useEffect and make code cleaner over all

You're using useEffect wrong, i suggest u take a look at the Rules of Hooks

Don't call Hooks inside loops, conditions, or nested functions.

I followed what Andom Miltev said about triggering the async function directly in my callback and it now works smoothly - thank you everyone for the help :)

    import React, { useState, useEffect } from "react";
import { Typography, Button } from "@material-ui/core";

import Navigation from "../Navigation";
export default function RandomJoke() {
  const [isLoaded, setLoaded] = useState(false);
  const [jokeData, setJokeData] = useState({});

  async function fetchMyAPI() {
    setLoaded(false);
    let response = await fetch("https://icanhazdadjoke.com/slack");
    response = await response.json();
    setJokeData(response);
    setLoaded(true);
    console.log("fired 1");
  }

  useEffect(() => {
    fetchMyAPI();
  }, []);

  return (
    <>
      <Navigation mainpage="RandomJoke" />

      <Typography variant="h6">Random Dad Joke</Typography>
      {isLoaded && <div>{jokeData.attachments[0].text}</div>}
      {!isLoaded && <div>loading...</div>}
      {isLoaded && (
        <Button variant="contained" onClick={() => fetchMyAPI()}>
          New one
        </Button>
      )}
    </>
  );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM