Home > Back-end >  How can I trigger the useEffect() hook with a button?
How can I trigger the useEffect() hook with a button?

Time:01-21

I have the following code, that loads a random user from an API. On load, it shows the first name of the fetched user.

Now I want to fetch a new user when clicking the 'Generate user' button, but it's not triggering the useEffect.

I thought I could trigger a refresh by passing the generate var to the dependency array in the useEffect, but it's not working. Should I make generate part of the state? That seems counter-intuitive for a simple toggle.

Any help / tips appreciated!

import { useEffect, useState } from "react";

const Async = () => {

    let generate = false;
    const [user, setUser] = useState({name: ''});

    useEffect(() => {
        fetch('https://randomuser.me/api/?results=1')
        .then(response => response.json())
        .then(data => setUser({...user, ['name']: data.results[0].name.first}))
        .catch(error => console.error(error));
    }, [generate]);
    
    function newUser()
    {
        generate = !generate;
    }

    return <>
        <button onClick={newUser}>Generate user</button>
        <div>User {user.name}</div>
    </>;

};

CodePudding user response:

Use your Generate With State as Below...

export default function App() {

const [user, setUser] = useState({name: ''});
const [generate,setGenerate] = useState(false)

useEffect(() => {

    fetch('https://randomuser.me/api/?results=1')
    .then(response => response.json())
    .then(data => setUser({...user, ['name']: data.results[0].name.first}))
    .catch(error => console.error(error));
}, [generate]);

function newUser()
{
    setGenerate(!generate)
}

return <>
    <button onClick={newUser}>Generate user</button>
    <div>User {user.name}</div>
</>;

}

CodePudding user response:

You could move generate into a React state that is toggled and triggers a rerender, but it would be better to just abstract the fetch call into a callback that is called by the button element's onClick handler. Call the function once in a mounting useEffect hook.

import { useEffect, useState } from "react";

const Async = () => {
  const [user, setUser] = useState({ name: '' });

  const generate = () => {
    fetch('https://randomuser.me/api/?results=1')
      .then(response => response.json())
      .then(data => setUser(user => ({
        ...user,
        name: data.results[0].name.first
      })))
      .catch(error => console.error(error));
  };

  // Call once when the component mounts
  useEffect(() => {
    generate();
  }, []);
    
  return (
    <>
      <button onClick={generate}>Generate user</button>
      <div>User {user.name}</div>
    </>
  );
};

CodePudding user response:

Move your request outside or into a reusable function

const reqData = () => {
  // return fetch req
}

const Comp = () => {
  useEffec(() => {
    reqData(); // assign it or whatever you need
  }, [])

  const handleClick = useCallback(reqData);

  return (
    <>
      <button onClick={handleCallback}>Generate user</button>
      <div>User {user.name}</div>
    </>
  )
}

This is just psudo code, you will have to set up arguments etc to get it to work, but this will allow you to make more calls per click while also having the content access to the initial load call.

CodePudding user response:

Instead of calling api in useEffect you can call it inside a function

import { useEffect, useState } from "react";

const Async = () => {

    let generate = false;
    const [user, setUser] = useState({name: ''});

    useEffect(() => {
        newUser()
    }, []);
    function newUser()
    {
        fetch('https://randomuser.me/api/?results=1')
        .then(response => response.json())
        .then(data => setUser({...user, ['name']: data.results[0].name.first}))
        .catch(error => console.error(error));
    }

    return <>
        <button onClick={newUser}>Generate user</button>
        <div>User {user.name}</div>
    </>;

};

And if you want to go with your code only then put genrate as state like

import { useEffect, useState } from "react";

const Async = () => {

    let [generate, setGenerate] = useState(true);
    const [user, setUser] = useState({name: ''});

    useEffect(() => {
        fetch('https://randomuser.me/api/?results=1')
        .then(response => response.json())
        .then(data => setUser({...user, ['name']: data.results[0].name.first}))
        .catch(error => console.error(error));
    }, [generate]);
    
    function newUser()
    {
        setGenerate(!generate)
    }

    return <>
        <button onClick={newUser}>Generate user</button>
        <div>User {user.name}</div>
    </>;

};
  • Related