React Hooks can only be called inside the body of a function component











up vote
2
down vote

favorite












How do I trigger useEffect() on a button click, rather than on rendering the component?



When I use it inside a function like this, I get an error stating:




Hooks can only be called inside the body of a function component




function App() {

function buttonClicked() {
useEffect(() => {
// Fetch from API
});
}

return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">App Title</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<button onClick={buttonClicked}>Make API Call</button>
</div>
);
}









share|improve this question




























    up vote
    2
    down vote

    favorite












    How do I trigger useEffect() on a button click, rather than on rendering the component?



    When I use it inside a function like this, I get an error stating:




    Hooks can only be called inside the body of a function component




    function App() {

    function buttonClicked() {
    useEffect(() => {
    // Fetch from API
    });
    }

    return (
    <div className="App">
    <header className="App-header">
    <img src={logo} className="App-logo" alt="logo" />
    <h1 className="App-title">App Title</h1>
    </header>
    <p className="App-intro">
    To get started, edit <code>src/App.js</code> and save to reload.
    </p>
    <button onClick={buttonClicked}>Make API Call</button>
    </div>
    );
    }









    share|improve this question


























      up vote
      2
      down vote

      favorite









      up vote
      2
      down vote

      favorite











      How do I trigger useEffect() on a button click, rather than on rendering the component?



      When I use it inside a function like this, I get an error stating:




      Hooks can only be called inside the body of a function component




      function App() {

      function buttonClicked() {
      useEffect(() => {
      // Fetch from API
      });
      }

      return (
      <div className="App">
      <header className="App-header">
      <img src={logo} className="App-logo" alt="logo" />
      <h1 className="App-title">App Title</h1>
      </header>
      <p className="App-intro">
      To get started, edit <code>src/App.js</code> and save to reload.
      </p>
      <button onClick={buttonClicked}>Make API Call</button>
      </div>
      );
      }









      share|improve this question















      How do I trigger useEffect() on a button click, rather than on rendering the component?



      When I use it inside a function like this, I get an error stating:




      Hooks can only be called inside the body of a function component




      function App() {

      function buttonClicked() {
      useEffect(() => {
      // Fetch from API
      });
      }

      return (
      <div className="App">
      <header className="App-header">
      <img src={logo} className="App-logo" alt="logo" />
      <h1 className="App-title">App Title</h1>
      </header>
      <p className="App-intro">
      To get started, edit <code>src/App.js</code> and save to reload.
      </p>
      <button onClick={buttonClicked}>Make API Call</button>
      </div>
      );
      }






      javascript reactjs react-hooks






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 11 at 21:30









      Yangshun Tay

      8,42953565




      8,42953565










      asked Nov 11 at 13:37









      Alan

      3,61031624




      3,61031624
























          2 Answers
          2






          active

          oldest

          votes

















          up vote
          2
          down vote



          accepted










          Sounds like you misunderstood the usage of useEffect. It's like componentDidUpdate hook - it is being triggered depending on value change, not directly by some function. When render method is called, useEffect is also called. Hard to tell what is your goal, but from your snippet it makes most sense just to call fetch without any hook. But to answer your question, one way to trigger useEffect would be to update your state and you can create useEffect hook to be triggered only if value of particular property is changed:



          const [buttonClicked, setButtonClicked] = useState(false);

          useEffect(() => {
          // Fetch from API
          }, [buttonClicked]);

          <button onClick={() => setButtonClicked(true)}>Make API Call</button>


          Now when you click, useEffect should be triggered, but because you added , [buttonClicked], it won't be called if any other property value changes.






          share|improve this answer





















          • From the docs: "The Effect Hook lets you perform side effects in function components". My goal is to perform a side effect on button click, not on render. Your solution with the state assumes I only want to perform a side effect on the first button click, what if I want perform it on every click? Also creating state variable simply to trigger useEffect seems clunky?
            – Alan
            Nov 11 at 17:48










          • So not uses this hook. If you invoke Http request from buttonClicked, it is considered as side-effect. If you for some reason still need to use useEffect hook, replace setButtonClicked(true) with setButtonClicked(!buttonClicked) - hook will be called every time button clicked
            – SkyHigh
            Nov 11 at 18:26












          • Ah ok, I was assuming useEffect was to wrap all side effects for functional components. I'll just avoid using and avoid setting state so, thanks.
            – Alan
            Nov 11 at 18:47




















          up vote
          3
          down vote













          The accepted answer isn't exactly correct IMO. If your goal is to trigger data fetching upon clicking on a button, there's no need for useEffect. useEffect is used to replace the lifecycle hooks - componentDidMount, componentDidUpdate, and componentWillUnmount.



          Think about this - without hooks, will you need these lifecycle hooks at all to achieve what you want? With classes, you simply have to use this.state and a callback that triggers upon clicking of the button; you wouldn't use any of these lifecycle hooks.



          The side effect you want to achieve is data fetching, but that's a user-triggered effect and useEffect is not helpful here. useEffect is only helpful when you want to have side effects during the lifecycle of the component.



          The code below should do what you want to achieve with hooks, and you don't need useEffect, you only need useState.






          function App() {
          const [user, setUser] = React.useState(null);

          function fetchData() {
          fetch('https://randomuser.me/api/')
          .then(results => results.json())
          .then(data => {
          setUser(data.results[0]);
          });
          };

          return <div>
          <p>{user ? user.name.first : 'No data'}</p>
          <button onClick={fetchData}>Fetch Data</button>
          </div>;
          }

          ReactDOM.render(<App/>, document.getElementById('app'));

          <script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
          <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

          <div id="app"></div>








          share|improve this answer





















            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53249297%2freact-hooks-can-only-be-called-inside-the-body-of-a-function-component%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            2
            down vote



            accepted










            Sounds like you misunderstood the usage of useEffect. It's like componentDidUpdate hook - it is being triggered depending on value change, not directly by some function. When render method is called, useEffect is also called. Hard to tell what is your goal, but from your snippet it makes most sense just to call fetch without any hook. But to answer your question, one way to trigger useEffect would be to update your state and you can create useEffect hook to be triggered only if value of particular property is changed:



            const [buttonClicked, setButtonClicked] = useState(false);

            useEffect(() => {
            // Fetch from API
            }, [buttonClicked]);

            <button onClick={() => setButtonClicked(true)}>Make API Call</button>


            Now when you click, useEffect should be triggered, but because you added , [buttonClicked], it won't be called if any other property value changes.






            share|improve this answer





















            • From the docs: "The Effect Hook lets you perform side effects in function components". My goal is to perform a side effect on button click, not on render. Your solution with the state assumes I only want to perform a side effect on the first button click, what if I want perform it on every click? Also creating state variable simply to trigger useEffect seems clunky?
              – Alan
              Nov 11 at 17:48










            • So not uses this hook. If you invoke Http request from buttonClicked, it is considered as side-effect. If you for some reason still need to use useEffect hook, replace setButtonClicked(true) with setButtonClicked(!buttonClicked) - hook will be called every time button clicked
              – SkyHigh
              Nov 11 at 18:26












            • Ah ok, I was assuming useEffect was to wrap all side effects for functional components. I'll just avoid using and avoid setting state so, thanks.
              – Alan
              Nov 11 at 18:47

















            up vote
            2
            down vote



            accepted










            Sounds like you misunderstood the usage of useEffect. It's like componentDidUpdate hook - it is being triggered depending on value change, not directly by some function. When render method is called, useEffect is also called. Hard to tell what is your goal, but from your snippet it makes most sense just to call fetch without any hook. But to answer your question, one way to trigger useEffect would be to update your state and you can create useEffect hook to be triggered only if value of particular property is changed:



            const [buttonClicked, setButtonClicked] = useState(false);

            useEffect(() => {
            // Fetch from API
            }, [buttonClicked]);

            <button onClick={() => setButtonClicked(true)}>Make API Call</button>


            Now when you click, useEffect should be triggered, but because you added , [buttonClicked], it won't be called if any other property value changes.






            share|improve this answer





















            • From the docs: "The Effect Hook lets you perform side effects in function components". My goal is to perform a side effect on button click, not on render. Your solution with the state assumes I only want to perform a side effect on the first button click, what if I want perform it on every click? Also creating state variable simply to trigger useEffect seems clunky?
              – Alan
              Nov 11 at 17:48










            • So not uses this hook. If you invoke Http request from buttonClicked, it is considered as side-effect. If you for some reason still need to use useEffect hook, replace setButtonClicked(true) with setButtonClicked(!buttonClicked) - hook will be called every time button clicked
              – SkyHigh
              Nov 11 at 18:26












            • Ah ok, I was assuming useEffect was to wrap all side effects for functional components. I'll just avoid using and avoid setting state so, thanks.
              – Alan
              Nov 11 at 18:47















            up vote
            2
            down vote



            accepted







            up vote
            2
            down vote



            accepted






            Sounds like you misunderstood the usage of useEffect. It's like componentDidUpdate hook - it is being triggered depending on value change, not directly by some function. When render method is called, useEffect is also called. Hard to tell what is your goal, but from your snippet it makes most sense just to call fetch without any hook. But to answer your question, one way to trigger useEffect would be to update your state and you can create useEffect hook to be triggered only if value of particular property is changed:



            const [buttonClicked, setButtonClicked] = useState(false);

            useEffect(() => {
            // Fetch from API
            }, [buttonClicked]);

            <button onClick={() => setButtonClicked(true)}>Make API Call</button>


            Now when you click, useEffect should be triggered, but because you added , [buttonClicked], it won't be called if any other property value changes.






            share|improve this answer












            Sounds like you misunderstood the usage of useEffect. It's like componentDidUpdate hook - it is being triggered depending on value change, not directly by some function. When render method is called, useEffect is also called. Hard to tell what is your goal, but from your snippet it makes most sense just to call fetch without any hook. But to answer your question, one way to trigger useEffect would be to update your state and you can create useEffect hook to be triggered only if value of particular property is changed:



            const [buttonClicked, setButtonClicked] = useState(false);

            useEffect(() => {
            // Fetch from API
            }, [buttonClicked]);

            <button onClick={() => setButtonClicked(true)}>Make API Call</button>


            Now when you click, useEffect should be triggered, but because you added , [buttonClicked], it won't be called if any other property value changes.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Nov 11 at 15:47









            SkyHigh

            42716




            42716












            • From the docs: "The Effect Hook lets you perform side effects in function components". My goal is to perform a side effect on button click, not on render. Your solution with the state assumes I only want to perform a side effect on the first button click, what if I want perform it on every click? Also creating state variable simply to trigger useEffect seems clunky?
              – Alan
              Nov 11 at 17:48










            • So not uses this hook. If you invoke Http request from buttonClicked, it is considered as side-effect. If you for some reason still need to use useEffect hook, replace setButtonClicked(true) with setButtonClicked(!buttonClicked) - hook will be called every time button clicked
              – SkyHigh
              Nov 11 at 18:26












            • Ah ok, I was assuming useEffect was to wrap all side effects for functional components. I'll just avoid using and avoid setting state so, thanks.
              – Alan
              Nov 11 at 18:47




















            • From the docs: "The Effect Hook lets you perform side effects in function components". My goal is to perform a side effect on button click, not on render. Your solution with the state assumes I only want to perform a side effect on the first button click, what if I want perform it on every click? Also creating state variable simply to trigger useEffect seems clunky?
              – Alan
              Nov 11 at 17:48










            • So not uses this hook. If you invoke Http request from buttonClicked, it is considered as side-effect. If you for some reason still need to use useEffect hook, replace setButtonClicked(true) with setButtonClicked(!buttonClicked) - hook will be called every time button clicked
              – SkyHigh
              Nov 11 at 18:26












            • Ah ok, I was assuming useEffect was to wrap all side effects for functional components. I'll just avoid using and avoid setting state so, thanks.
              – Alan
              Nov 11 at 18:47


















            From the docs: "The Effect Hook lets you perform side effects in function components". My goal is to perform a side effect on button click, not on render. Your solution with the state assumes I only want to perform a side effect on the first button click, what if I want perform it on every click? Also creating state variable simply to trigger useEffect seems clunky?
            – Alan
            Nov 11 at 17:48




            From the docs: "The Effect Hook lets you perform side effects in function components". My goal is to perform a side effect on button click, not on render. Your solution with the state assumes I only want to perform a side effect on the first button click, what if I want perform it on every click? Also creating state variable simply to trigger useEffect seems clunky?
            – Alan
            Nov 11 at 17:48












            So not uses this hook. If you invoke Http request from buttonClicked, it is considered as side-effect. If you for some reason still need to use useEffect hook, replace setButtonClicked(true) with setButtonClicked(!buttonClicked) - hook will be called every time button clicked
            – SkyHigh
            Nov 11 at 18:26






            So not uses this hook. If you invoke Http request from buttonClicked, it is considered as side-effect. If you for some reason still need to use useEffect hook, replace setButtonClicked(true) with setButtonClicked(!buttonClicked) - hook will be called every time button clicked
            – SkyHigh
            Nov 11 at 18:26














            Ah ok, I was assuming useEffect was to wrap all side effects for functional components. I'll just avoid using and avoid setting state so, thanks.
            – Alan
            Nov 11 at 18:47






            Ah ok, I was assuming useEffect was to wrap all side effects for functional components. I'll just avoid using and avoid setting state so, thanks.
            – Alan
            Nov 11 at 18:47














            up vote
            3
            down vote













            The accepted answer isn't exactly correct IMO. If your goal is to trigger data fetching upon clicking on a button, there's no need for useEffect. useEffect is used to replace the lifecycle hooks - componentDidMount, componentDidUpdate, and componentWillUnmount.



            Think about this - without hooks, will you need these lifecycle hooks at all to achieve what you want? With classes, you simply have to use this.state and a callback that triggers upon clicking of the button; you wouldn't use any of these lifecycle hooks.



            The side effect you want to achieve is data fetching, but that's a user-triggered effect and useEffect is not helpful here. useEffect is only helpful when you want to have side effects during the lifecycle of the component.



            The code below should do what you want to achieve with hooks, and you don't need useEffect, you only need useState.






            function App() {
            const [user, setUser] = React.useState(null);

            function fetchData() {
            fetch('https://randomuser.me/api/')
            .then(results => results.json())
            .then(data => {
            setUser(data.results[0]);
            });
            };

            return <div>
            <p>{user ? user.name.first : 'No data'}</p>
            <button onClick={fetchData}>Fetch Data</button>
            </div>;
            }

            ReactDOM.render(<App/>, document.getElementById('app'));

            <script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
            <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

            <div id="app"></div>








            share|improve this answer

























              up vote
              3
              down vote













              The accepted answer isn't exactly correct IMO. If your goal is to trigger data fetching upon clicking on a button, there's no need for useEffect. useEffect is used to replace the lifecycle hooks - componentDidMount, componentDidUpdate, and componentWillUnmount.



              Think about this - without hooks, will you need these lifecycle hooks at all to achieve what you want? With classes, you simply have to use this.state and a callback that triggers upon clicking of the button; you wouldn't use any of these lifecycle hooks.



              The side effect you want to achieve is data fetching, but that's a user-triggered effect and useEffect is not helpful here. useEffect is only helpful when you want to have side effects during the lifecycle of the component.



              The code below should do what you want to achieve with hooks, and you don't need useEffect, you only need useState.






              function App() {
              const [user, setUser] = React.useState(null);

              function fetchData() {
              fetch('https://randomuser.me/api/')
              .then(results => results.json())
              .then(data => {
              setUser(data.results[0]);
              });
              };

              return <div>
              <p>{user ? user.name.first : 'No data'}</p>
              <button onClick={fetchData}>Fetch Data</button>
              </div>;
              }

              ReactDOM.render(<App/>, document.getElementById('app'));

              <script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
              <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

              <div id="app"></div>








              share|improve this answer























                up vote
                3
                down vote










                up vote
                3
                down vote









                The accepted answer isn't exactly correct IMO. If your goal is to trigger data fetching upon clicking on a button, there's no need for useEffect. useEffect is used to replace the lifecycle hooks - componentDidMount, componentDidUpdate, and componentWillUnmount.



                Think about this - without hooks, will you need these lifecycle hooks at all to achieve what you want? With classes, you simply have to use this.state and a callback that triggers upon clicking of the button; you wouldn't use any of these lifecycle hooks.



                The side effect you want to achieve is data fetching, but that's a user-triggered effect and useEffect is not helpful here. useEffect is only helpful when you want to have side effects during the lifecycle of the component.



                The code below should do what you want to achieve with hooks, and you don't need useEffect, you only need useState.






                function App() {
                const [user, setUser] = React.useState(null);

                function fetchData() {
                fetch('https://randomuser.me/api/')
                .then(results => results.json())
                .then(data => {
                setUser(data.results[0]);
                });
                };

                return <div>
                <p>{user ? user.name.first : 'No data'}</p>
                <button onClick={fetchData}>Fetch Data</button>
                </div>;
                }

                ReactDOM.render(<App/>, document.getElementById('app'));

                <script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
                <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

                <div id="app"></div>








                share|improve this answer












                The accepted answer isn't exactly correct IMO. If your goal is to trigger data fetching upon clicking on a button, there's no need for useEffect. useEffect is used to replace the lifecycle hooks - componentDidMount, componentDidUpdate, and componentWillUnmount.



                Think about this - without hooks, will you need these lifecycle hooks at all to achieve what you want? With classes, you simply have to use this.state and a callback that triggers upon clicking of the button; you wouldn't use any of these lifecycle hooks.



                The side effect you want to achieve is data fetching, but that's a user-triggered effect and useEffect is not helpful here. useEffect is only helpful when you want to have side effects during the lifecycle of the component.



                The code below should do what you want to achieve with hooks, and you don't need useEffect, you only need useState.






                function App() {
                const [user, setUser] = React.useState(null);

                function fetchData() {
                fetch('https://randomuser.me/api/')
                .then(results => results.json())
                .then(data => {
                setUser(data.results[0]);
                });
                };

                return <div>
                <p>{user ? user.name.first : 'No data'}</p>
                <button onClick={fetchData}>Fetch Data</button>
                </div>;
                }

                ReactDOM.render(<App/>, document.getElementById('app'));

                <script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
                <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

                <div id="app"></div>








                function App() {
                const [user, setUser] = React.useState(null);

                function fetchData() {
                fetch('https://randomuser.me/api/')
                .then(results => results.json())
                .then(data => {
                setUser(data.results[0]);
                });
                };

                return <div>
                <p>{user ? user.name.first : 'No data'}</p>
                <button onClick={fetchData}>Fetch Data</button>
                </div>;
                }

                ReactDOM.render(<App/>, document.getElementById('app'));

                <script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
                <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

                <div id="app"></div>





                function App() {
                const [user, setUser] = React.useState(null);

                function fetchData() {
                fetch('https://randomuser.me/api/')
                .then(results => results.json())
                .then(data => {
                setUser(data.results[0]);
                });
                };

                return <div>
                <p>{user ? user.name.first : 'No data'}</p>
                <button onClick={fetchData}>Fetch Data</button>
                </div>;
                }

                ReactDOM.render(<App/>, document.getElementById('app'));

                <script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
                <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

                <div id="app"></div>






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 11 at 21:22









                Yangshun Tay

                8,42953565




                8,42953565






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53249297%2freact-hooks-can-only-be-called-inside-the-body-of-a-function-component%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Full-time equivalent

                    さくらももこ

                    13 indicted, 8 arrested in Calif. drug cartel investigation