Atieh Hamidi
Atieh Hamidi

Reputation: 13

my Button in react dosen't work - I use useState and useEffect

I am not sure why my Button dosen't work, I use useState and useEffect

here is my code:

    import React, { useState, useEffect } from "react";
    // import Timeout from "await-timeout";
    import axios from "axios";
    
    export default function Dogs() {
      const [dog, set_Dog] = useState(" ");
      console.log({ dog });
    
      useEffect(() => {
        async function getFetch() {
          const res = await axios.get("https://dog.ceo/api/breeds/image/random");
          const {
            data: { message },
          } = res;
          console.log("Got back", message);
          set_Dog(message);
        }
        getFetch();
      }, []);
    
      function output() {
        set_Dog(dog);
        // console.log(set_Dog({ dog }));
      }
      return (
        <div>
          <h2>If you like Dogs,{dog} Press Button</h2>
          <button onClick={output}>Click me</button>
          {dog}
          <img src={dog} />
        </div>
      );
    }`

when I click on the button the image be disappeared, I want to show a new image of the dog without refresh my browser

Upvotes: 1

Views: 79

Answers (3)

Romain Constantin
Romain Constantin

Reputation: 184

Try : onClick={() => output()}

Like that it only renders when you clicking on the button and not everytime the component re-render.

Upvotes: 0

Fatih
Fatih

Reputation: 11

You can use useRef to keep a reference to your function after fetching the first image.

const click_ref = React.useRef(null);
useEffect(() => {
    async function getFetch() {
      const res = await axios.get("https://dog.ceo/api/breeds/image/random");
      const {
        data: { message },
      } = res;
      console.log("Got back", message);
      set_Dog(message);
    }
    getFetch();
    click_ref.current = getFetch;
  }, []);
<button onClick={() => click_ref.current()}>Click me</button>

Upvotes: 1

subashMahapatra
subashMahapatra

Reputation: 6837

The value of dog which is being set on the in the function output never changes because of stale closure.

Because you want to populate the state on mount and also change it when user clicks on a button, you have to create the function which calls the API in the function scope and memoize it with useCallback, the same function can be passed to the onClick. For example,

export default function Dogs() {
  const [dog, set_Dog] = useState("");
  console.log({ dog });

  const getDogPic = useCallback(async () => {
    const res = await axios.get("https://dog.ceo/api/breeds/image/random");
    const {
      data: { message }
    } = res;
    console.log("Got back", message);
    set_Dog(message);
  }, []);

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

  return (
    <div>
      <h2>If you like Dogs,{dog} Press Button</h2>
      <button onClick={getDogPic}>Click me</button>
      {dog}
      <img src={dog} alt={"dog-pic"} />
    </div>
  );
}

Working demo in codesandbox

Read more about stale-closures

Upvotes: 1

Related Questions