Hook rule
Use Hook only at the top
- Do not call Hook in loops, conditions, or nested functions to ensure that they are always invoked at the top level of your React function. By following this rule, you can ensure that hooks are called in the same order in each rendering. This allows react to maintain the correct hook state between multiple useState and useEffect calls
Call Hook only in React function
- Do not call Hook in the ordinary JavaScript function. You can:
✅ Calling Hook in the function component of React
✅ Call other Hook in custom Hook
How does React know which state corresponds to which useState?
The answer is that React depends on the order of Hook calls.
// ------------ // First render // ------------ useState('Mary') // 1. Use 'Mary' to initialize the state variable named name useEffect(persistForm) // 2. Add effect to save the form operation useState('Poppins') // 3. Use 'Poppins' to initialize the state with the variable name surname useEffect(updateTitle) // 4. Add effect to update the title // ------------- // Secondary rendering // ------------- useState('Mary') // 1. Read the state of the variable name name (the parameter is ignored) useEffect(persistForm) // 2. Replace the effect of the saved form useState('Poppins') // 3. Read the state of the variable named surname (the parameter is ignored) useEffect(updateTitle) // 4. Replace the effect of the updated title // ...
This is why Hook needs to be called at the top level of our component. If we want to execute an effect conditionally, we can put the judgment inside the Hook:
useEffect(function persistForm() { // 👍 Place conditional judgment in effect if (name !== '') { localStorage.setItem('formData', name); } });
Customize Hook
By customizing the Hook, you can extract component logic into reusable functions
Custom Hook is a function whose name starts with use. Other hooks can be called inside the function
- Define custom Hook
import { useState, useEffect } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); useEffect(() => { function handleStatusChange(status) { setIsOnline(status.isOnline); } ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange); }; }); return isOnline; }
- Use custom Hook
function FriendStatus(props) { const isOnline = useFriendStatus(props.friend.id); if (isOnline === null) { return 'Loading...'; } return isOnline ? 'Online' : 'Offline'; }
function FriendListItem(props) { const isOnline = useFriendStatus(props.friend.id); return ( <li style={{ color: isOnline ? 'green' : 'black' }}> {props.friend.name} </li> ); }
Must the custom Hook start with "use"?
It must be. This agreement is very important.
If you don't follow it, because you can't judge whether a function contains a call to its internal Hook, React will not be able to automatically check whether your Hook violates the Hook rules.
Will using the same Hook in both components share the state?
can't. Custom Hook is a mechanism for reusing state logic (for example, setting it as a subscription and storing the current value), so every time you use a custom Hook, all States and side effects are completely isolated.
How can a custom Hook get an independent state?
Each time Hook is called, it gets an independent state. Since we directly call useFriendStatus, from the perspective of React, our component only calls useState and useEffect.
As we learned in the previous chapters, we can call useState and useEffect multiple times in a component, which are completely independent.