React is responsible for rendering components and Hooks when necessary to optimize the user experience. It is declarative: you tell React what to render in your component’s logic, and React will figure out how best to display it to your user.
Components should only be used in JSX. Don’t call them as regular functions. React should call it.
React must decide when your component function is called during rendering. In React, you do this using JSX.
function BlogPost() {
return <Layout><Article /></Layout>; // ✅ Good: Only use components in JSX
} function BlogPost() {
return <Layout>{Article()}</Layout>; // 🔴 Bad: Never call them directly
} If a component contains Hooks, it’s easy to violate the Rules of Hooks when components are called directly in a loop or conditionally.
Letting React orchestrate rendering also allows a number of benefits:
<Feed> to the <Profile> page, React won’t attempt to re-use them.Hooks should only be called inside of components or Hooks. Never pass it around as a regular value.
Hooks allow you to augment a component with React features. They should always be called as a function, and never passed around as a regular value. This enables local reasoning, or the ability for developers to understand everything a component can do by looking at that component in isolation.
Breaking this rule will cause React to not automatically optimize your component.
Hooks should be as “static” as possible. This means you shouldn’t dynamically mutate them. For example, this means you shouldn’t write higher order Hooks:
function ChatInput() {
const useDataWithLogging = withLogging(useData); // 🔴 Bad: don't write higher order Hooks
const data = useDataWithLogging();
} Hooks should be immutable and not be mutated. Instead of mutating a Hook dynamically, create a static version of the Hook with the desired functionality.
function ChatInput() {
const data = useDataWithLogging(); // ✅ Good: Create a new version of the Hook
}
function useDataWithLogging() {
// ... Create a new version of the Hook and inline the logic here
} Hooks should also not be dynamically used: for example, instead of doing dependency injection in a component by passing a Hook as a value:
function ChatInput() {
return <Button useData={useDataWithLogging} /> // 🔴 Bad: don't pass Hooks as props
} You should always inline the call of the Hook into that component and handle any logic in there.
function ChatInput() {
return <Button />
}
function Button() {
const data = useDataWithLogging(); // ✅ Good: Use the Hook directly
}
function useDataWithLogging() {
// If there's any conditional logic to change the Hook's behavior, it should be inlined into
// the Hook
} This way, <Button /> is much easier to understand and debug. When Hooks are used in dynamic ways, it increases the complexity of your app greatly and inhibits local reasoning, making your team less productive in the long term. It also makes it easier to accidentally break the Rules of Hooks that Hooks should not be called conditionally. If you find yourself needing to mock components for tests, it’s better to mock the server instead to respond with canned data. If possible, it’s also usually more effective to test your app with end-to-end tests.
© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://react.dev/reference/rules/react-calls-components-and-hooks