🎣 Custom Hooks: Your Superpower Toolbox
Imagine you have a magic backpack. Every time you need something—a flashlight, a snack, a map—you just reach in and pull it out. Custom Hooks are exactly like that magic backpack for your React Native app!
🌟 What Are Custom Hooks?
Think of your app like building with LEGO blocks. Sometimes you build the same little structure over and over—like a tiny door or window. Wouldn’t it be nice to have that piece ready-made?
Custom Hooks = Your Ready-Made LEGO Pieces
They let you take code you use again and again, wrap it up in a neat package, and use it anywhere you want!
// Without custom hook (messy, repeated)
const [count, setCount] = useState(0);
useEffect(() => { /* same code */ }, []);
// With custom hook (clean, reusable)
const count = useCounter();
🏗️ Building Custom Hooks
The Magic Recipe
Every custom hook follows a simple recipe:
- Start with “use” - Like
useCounter,useFetch,useForm - Put your logic inside - All the useState, useEffect stuff
- Return what you need - Give back values or functions
Your First Custom Hook
Let’s build a simple counter hook!
// useCounter.js
function useCounter(start = 0) {
const [count, setCount] = useState(start);
const add = () => setCount(c => c + 1);
const subtract = () => setCount(c => c - 1);
const reset = () => setCount(start);
return { count, add, subtract, reset };
}
Using it is SO easy:
function MyScreen() {
const { count, add, reset } = useCounter(10);
return (
<View>
<Text>Count: {count}</Text>
<Button onPress={add} title="Add" />
<Button onPress={reset} title="Reset" />
</View>
);
}
Real-World Example: useFetch Hook
Fetching data? Let’s make it simple forever!
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch(url)
.then(res => res.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [url]);
return { data, loading, error };
}
Now fetching data is a breeze:
function UserList() {
const { data, loading, error } =
useFetch('https://api.example.com/users');
if (loading) return <Text>Loading...</Text>;
if (error) return <Text>Oops! Error</Text>;
return <FlatList data={data} />;
}
🎠Hook Composition
Hooks Playing Together
Remember how LEGO pieces connect? Custom hooks can use OTHER hooks—including other custom hooks!
graph TD A["useAuth"] --> B["useState"] A --> C["useEffect"] A --> D["useStorage"] D --> E["useState"] D --> F["AsyncStorage"]
Building Complex Hooks from Simple Ones
Step 1: A simple storage hook
function useStorage(key) {
const [value, setValue] = useState(null);
useEffect(() => {
AsyncStorage.getItem(key)
.then(setValue);
}, [key]);
const save = (newValue) => {
setValue(newValue);
AsyncStorage.setItem(key, newValue);
};
return [value, save];
}
Step 2: Compose into auth hook
function useAuth() {
const [token, setToken] = useStorage('auth_token');
const [user, setUser] = useState(null);
const login = async (email, password) => {
const response = await api.login(email, password);
setToken(response.token);
setUser(response.user);
};
const logout = () => {
setToken(null);
setUser(null);
};
return { user, token, login, logout };
}
The Power of Composition
| Simple Hook | + Simple Hook | = Powerful Hook |
|---|---|---|
| useStorage | useState | useAuth |
| useFetch | useDebounce | useSearch |
| useState | useEffect | useForm |
📜 Rules of Hooks
The Three Golden Rules
Think of these rules like the rules of a board game. Break them, and the game won’t work!
Rule 1: Only Call at the Top Level
Never call hooks inside loops, conditions, or nested functions.
// ❌ BAD - Inside condition
function MyComponent({ isLoggedIn }) {
if (isLoggedIn) {
const [user, setUser] = useState(null);
}
}
// âś… GOOD - At the top level
function MyComponent({ isLoggedIn }) {
const [user, setUser] = useState(null);
if (isLoggedIn) {
// use user here
}
}
Why? React tracks hooks by their order. If you skip a hook sometimes, React gets confused!
graph TD A["First Render"] --> B["Hook 1: useState"] B --> C["Hook 2: useEffect"] C --> D["Hook 3: useState"] E["Second Render"] --> F["Hook 1: useState"] F --> G["Hook 2: useEffect"] G --> H["Hook 3: useState"] style A fill:#90EE90 style E fill:#90EE90
Rule 2: Only Call from React Functions
Call hooks from:
- React function components
- Custom hooks
Never from:
- Regular JavaScript functions
- Class components
// ❌ BAD - Regular function
function calculateTotal() {
const [items] = useState([]);
return items.reduce((a, b) => a + b, 0);
}
// âś… GOOD - Custom hook
function useTotal() {
const [items] = useState([]);
return items.reduce((a, b) => a + b, 0);
}
Rule 3: Name Custom Hooks with “use”
Always start your custom hook names with “use”.
// ❌ BAD
function getWindowSize() { ... }
function fetchData() { ... }
// âś… GOOD
function useWindowSize() { ... }
function useFetch() { ... }
Why? This tells React “Hey, this follows hook rules!” and enables linting tools to catch mistakes.
🎯 Quick Summary
| Concept | What It Means | Example |
|---|---|---|
| Building | Wrap reusable logic in a function starting with “use” | useCounter() |
| Composition | Hooks can use other hooks | useAuth uses useStorage |
| Top Level | Always call hooks at the top of your component | Not in if or for |
| React Only | Only in components or custom hooks | Not in regular functions |
| Use Prefix | Name custom hooks with “use” | useForm, not formHelper |
🚀 You’re Now a Hook Hero!
Custom hooks are like having a superpower. You can:
- ✨ Reuse logic across your entire app
- đź§ą Keep components clean and focused
- đź”— Compose simple hooks into powerful ones
- 🎮 Share hooks with your team or the world
Remember the three rules, and you’ll never go wrong. Now go build something amazing!
“The best code is code you don’t have to write twice.” — Every happy developer ever
