Movatterモバイル変換


[0]ホーム

URL:


We want to hear from you!Take our 2021 Community Survey!
This site is no longer updated.Go to react.dev

Rules of Hooks

These docs are old and won’t be updated. Go toreact.dev for the new React docs.

These new documentation pages teach modern React and include live examples:

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class.

Hooks are JavaScript functions, but you need to follow two rules when using them. We provide alinter plugin to enforce these rules automatically:

Only Call Hooks at the Top Level

Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multipleuseState anduseEffect calls. (If you’re curious, we’ll explain this in depthbelow.)

Only Call Hooks from React Functions

Don’t call Hooks from regular JavaScript functions. Instead, you can:

  • ✅ Call Hooks from React function components.
  • ✅ Call Hooks from custom Hooks (we’ll learn about themon the next page).

By following this rule, you ensure that all stateful logic in a component is clearly visible from its source code.

ESLint Plugin

We released an ESLint plugin calledeslint-plugin-react-hooks that enforces these two rules. You can add this plugin to your project if you’d like to try it:

This plugin is included by default inCreate React App.

npminstall eslint-plugin-react-hooks --save-dev
// Your ESLint configuration{"plugins":[// ..."react-hooks"],"rules":{// ..."react-hooks/rules-of-hooks":"error",// Checks rules of Hooks"react-hooks/exhaustive-deps":"warn"// Checks effect dependencies}}

You can skip to the next page explaining how to writeyour own Hooks now. On this page, we’ll continue by explaining the reasoning behind these rules.

Explanation

As welearned earlier, we can use multiple State or Effect Hooks in a single component:

functionForm(){// 1. Use the name state variableconst[name, setName]=useState('Mary');// 2. Use an effect for persisting the formuseEffect(functionpersistForm(){    localStorage.setItem('formData', name);});// 3. Use the surname state variableconst[surname, setSurname]=useState('Poppins');// 4. Use an effect for updating the titleuseEffect(functionupdateTitle(){    document.title= name+' '+ surname;});// ...}

So how does React know which state corresponds to whichuseState call? The answer is thatReact relies on the order in which Hooks are called. Our example works because the order of the Hook calls is the same on every render:

// ------------// First render// ------------useState('Mary')// 1. Initialize the name state variable with 'Mary'useEffect(persistForm)// 2. Add an effect for persisting the formuseState('Poppins')// 3. Initialize the surname state variable with 'Poppins'useEffect(updateTitle)// 4. Add an effect for updating the title// -------------// Second render// -------------useState('Mary')// 1. Read the name state variable (argument is ignored)useEffect(persistForm)// 2. Replace the effect for persisting the formuseState('Poppins')// 3. Read the surname state variable (argument is ignored)useEffect(updateTitle)// 4. Replace the effect for updating the title// ...

As long as the order of the Hook calls is the same between renders, React can associate some local state with each of them. But what happens if we put a Hook call (for example, thepersistForm effect) inside a condition?

// 🔴 We're breaking the first rule by using a Hook in a conditionif(name!==''){useEffect(functionpersistForm(){      localStorage.setItem('formData', name);});}

Thename !== '' condition istrue on the first render, so we run this Hook. However, on the next render the user might clear the form, making the conditionfalse. Now that we skip this Hook during rendering, the order of the Hook calls becomes different:

useState('Mary')// 1. Read the name state variable (argument is ignored)// useEffect(persistForm)  // 🔴 This Hook was skipped!useState('Poppins')// 🔴 2 (but was 3). Fail to read the surname state variableuseEffect(updateTitle)// 🔴 3 (but was 4). Fail to replace the effect

React wouldn’t know what to return for the seconduseState Hook call. React expected that the second Hook call in this component corresponds to thepersistForm effect, just like during the previous render, but it doesn’t anymore. From that point, every next Hook call after the one we skipped would also shift by one, leading to bugs.

This is why Hooks must be called on the top level of our components. If we want to run an effect conditionally, we can put that conditioninside our Hook:

useEffect(functionpersistForm(){// 👍 We're not breaking the first rule anymoreif(name!==''){      localStorage.setItem('formData', name);}});

Note that you don’t need to worry about this problem if you use theprovided lint rule. But now you also knowwhy Hooks work this way, and which issues the rule is preventing.

Next Steps

Finally, we’re ready to learn aboutwriting your own Hooks! Custom Hooks let you combine Hooks provided by React into your own abstractions, and reuse common stateful logic between different components.

Is this page useful?Edit this page

[8]ページ先頭

©2009-2025 Movatter.jp