skip to Main Content

In this react component how come usestate is working inside a regular function regfunc? It should throw some kind of error but it isn’t.

import { useState } from "react";

export function App() {
  let regfunc = () => {
    const [color, setColor] = useState("hellojo");
  };
  return (
    <div className="App">
      
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

2

Answers


  1. Hooks need to be declared at the top-level of a component declaration, but they can also be used inside of other hooks. They always have to be at the top-level inside of a function.

    Custom hooks

    Here is your component slightly rewritten.

    • I moved a outside of the App component
    • I renamed it to useColor (hooks should start with "use")

    The hook returns a string that can be rendered inside of App.

    import { useState } from "react";
    
    let useColor = () => {
      // eslint-disable-next-line no-unused-vars
      const [color, setColor] = useState("hellojo");
      return color;
    };
    
    export function App() {
      const b = useColor();
    
      return (
        <div className="App">
          {b}
          <h1>Hello CodeSandbox</h1>
          <h2>Start editing to see some magic happen!</h2>
        </div>
      );
    }
    
    const { useState } = React;
    
    let useColor = () => {
      // eslint-disable-next-line no-unused-vars
      const [color, setColor] = useState("hellojo");
      return color;
    };
    
    function App() {
      const color = useColor();
    
      return (
        <div className="App">
          {color}
          <h1>Hello CodeSandbox</h1>
          <h2>Start editing to see some magic happen!</h2>
        </div>
      );
    }
    
    ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    <div id="root"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>

    Function components

    The proper way to declare a component in React is to give it a PascalCase name and return some JSX.

    The proper way to do this would be to declare the ColorComponent outside of the app. You can memoize it to optimize performance and avoid unnecessary re-renders based on prop changes.

    // App.jsx
    import React, { useState } from "react";
    
    const ColorComponent = () => {
      // eslint-disable-next-line no-unused-vars
      const [color, setColor] = useState("hellojo");
      return color;
    };
    
    const MemoizedColorComponent = React.memo(ColorComponent);
    
    function App() {
      return (
        <div className="App">
          <MemoizedColorComponent />
        </div>
      );
    }
    
    export default App;
    
    const { useState } = React;
    
    const ColorComponent = () => {
      const [color, setColor] = useState("hellojo");
      return color;
    };
    
    const MemoizedColorComponent = React.memo(ColorComponent);
    
    function App() {
      return (
        <div className="App">
          <MemoizedColorComponent />
          <h1>Hello CodeSandbox</h1>
          <h2>Start editing to see some magic happen!</h2>
        </div>
      );
    }
    
    ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    <div id="root"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>

    Or move the component to its own file:

    // ColorComponent.jsx
    import React, { useState } from "react";
    
    const ColorComponent = () => {
      // eslint-disable-next-line no-unused-vars
      const [color, setColor] = useState("hellojo");
    
      return color;
    };
    
    export default ColorComponent;
    

    And importing it into your App.jsx.


    Summary

    As mentioned by others, as long as you adhere to the rules of Hooks in React, your function will be either treated as a custom hook or a function component.

    Rules of Hooks

    Hooks are defined using JavaScript functions, but they represent a special type of reusable UI logic with restrictions on where they can be called.

    Only call Hooks at the top level

    Functions whose names start with use are called Hooks in React.

    Don’t call Hooks inside loops, conditions, nested functions, or try/catch/finally blocks. Instead, always use Hooks at the top level of your React function, before any early returns. You can only call Hooks while React is rendering a function component:

    • ✅ Call them at the top level in the body of a function component.
    • ✅ Call them at the top level in the body of a custom Hook.
    function Counter() {
      // ✅ Good: top-level in a function component
      const [count, setCount] = useState(0);
      // ...
    }
    
    function useWindowWidth() {
      // ✅ Good: top-level in a custom Hook
      const [width, setWidth] = useState(window.innerWidth);
      // ...
    }
    

    It’s not supported to call Hooks (functions starting with use) in any other cases, for example:

    • 🔴 Do not call Hooks inside conditions or loops.
    • 🔴 Do not call Hooks after a conditional return statement.
    • 🔴 Do not call Hooks in event handlers.
    • 🔴 Do not call Hooks in class components.
    • 🔴 Do not call Hooks inside functions passed to useMemo, useReducer, or useEffect.
    • 🔴 Do not call Hooks inside try/catch/finally blocks.

    If you break these rules, you might see this error.

    function Bad({ cond }) {
      if (cond) {
        // 🔴 Bad: inside a condition (to fix, move it outside!)
        const theme = useContext(ThemeContext);
      }
      // ...
    }
    
    function Bad() {
      for (let i = 0; i < 10; i++) {
        // 🔴 Bad: inside a loop (to fix, move it outside!)
        const theme = useContext(ThemeContext);
      }
      // ...
    }
    
    function Bad({ cond }) {
      if (cond) {
        return;
      }
      // 🔴 Bad: after a conditional return (to fix, move it before > the return!)
      const theme = useContext(ThemeContext);
      // ...
    }
    
    function Bad() {
      function handleClick() {
        // 🔴 Bad: inside an event handler (to fix, move it outside!)
        const theme = useContext(ThemeContext);
      }
      // ...
    }
    
    function Bad() {
      const style = useMemo(() => {
        // 🔴 Bad: inside useMemo (to fix, move it outside!)
        const theme = useContext(ThemeContext);
        return createStyle(theme);
      });
      // ...
    }
    
    class Bad extends React.Component {
      render() {
        // 🔴 Bad: inside a class component (to fix, write a function > component instead of a class!)
        useEffect(() => {})
        // ...
      }
    }
    
    function Bad() {
      try {
        // 🔴 Bad: inside try/catch/finally block (to fix, move it > outside!)
        const [x, setX] = useState(0);
      } catch {
        const [x, setX] = useState(1);
      }
    }
    
    Login or Signup to reply.
  2. Can hooks be called inside the nested functions?

    No, from the rules-of-hooks:

    Don’t call Hooks inside loops, conditions, nested functions, or try/catch/finally blocks. Instead, always use Hooks at the top level of your React function, before any early returns. You can only call Hooks while React is rendering a function component:


    So it’s better to make the Color a custom component like so:

    const { useState } = React;
    
    const Color = () => {
        const [color, setColor] = useState("hellojo");
        return color;
    };
    
    const App = () => {
        return (
            <div className="App">
                <h1>Hello CodeSandbox</h1>
                <h2>Start editing to see some magic happen!</h2>
                <Color />
            </div>
        );
    };
    
    ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    <div id="root"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search