ReactJavaScriptWeb Development

Mastering React Hooks: Beyond the Basics

Take your React skills to the next level by mastering hooks with these advanced patterns and techniques.

5 min read
A
AnhDojo
Mastering React Hooks: Beyond the Basics

Mastering React Hooks: Beyond the Basics

React Hooks revolutionized how we write React components, enabling state and other React features without classes. While useState and useEffect are the gateway to hooks, there’s so much more to explore. Let’s dive into some advanced patterns.

Custom Hooks: Organizing Logic

Custom hooks are the perfect way to extract and reuse stateful logic between components. Here’s a useful hook for handling form state:

function useForm<T>(initialValues: T) {
const [values, setValues] = useState<T>(initialValues);
const [errors, setErrors] = useState<Partial<Record<keyof T, string>>>({});
const [touched, setTouched] = useState<Partial<Record<keyof T, boolean>>>({});
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const { name, value } = e.target;
setValues({
...values,
[name]: value,
});
// Clear error when field is modified
if (errors[name as keyof T]) {
setErrors({
...errors,
[name]: undefined,
});
}
};
const handleBlur = (
e: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const { name } = e.target;
setTouched({
...touched,
[name]: true,
});
};
const reset = () => {
setValues(initialValues);
setErrors({});
setTouched({});
};
return {
values,
errors,
touched,
handleChange,
handleBlur,
setValues,
setErrors,
reset,
};
}

useReducer for Complex State Logic

For complex state logic, useReducer provides a more structured approach:

type State = {
count: number;
step: number;
isRunning: boolean;
};
type Action =
| { type: "increment" }
| { type: "decrement" }
| { type: "setStep"; payload: number }
| { type: "reset" }
| { type: "toggleRunning" };
function reducer(state: State, action: Action): State {
switch (action.type) {
case "increment":
return { ...state, count: state.count + state.step };
case "decrement":
return { ...state, count: state.count - state.step };
case "setStep":
return { ...state, step: action.payload };
case "reset":
return { count: 0, step: 1, isRunning: false };
case "toggleRunning":
return { ...state, isRunning: !state.isRunning };
default:
return state;
}
}
// In your component:
const [state, dispatch] = useReducer(reducer, {
count: 0,
step: 1,
isRunning: false,
});

useCallback and useMemo for Performance

These hooks help prevent unnecessary renders by memoizing functions and values:

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
const memoizedCallback = useCallback(() => {
doSomethingWith(a, b);
}, [a, b]);

useRef Beyond DOM References

useRef is incredibly versatile beyond just DOM references:

// For storing previous values
function usePrevious<T>(value: T): T | undefined {
const ref = useRef<T>();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
// For interval timers
function useInterval(callback: () => void, delay: number | null) {
const savedCallback = useRef(callback);
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
if (delay === null) return;
const id = setInterval(() => savedCallback.current(), delay);
return () => clearInterval(id);
}, [delay]);
}

Context with Hooks for Global State

Creating and using context becomes much cleaner with hooks:

// Create the context
const ThemeContext = createContext({
theme: "light",
toggleTheme: () => {},
});
// Provider component
function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// Custom hook for consuming the context
function useTheme() {
const context = useContext(ThemeContext);
if (context === undefined) {
throw new Error("useTheme must be used within a ThemeProvider");
}
return context;
}

Conclusion

Mastering React hooks doesn’t happen overnight. It requires practice and experimentation to fully grasp their power. The patterns above will help you write more maintainable, reusable, and performant React code.

What’s your favorite hook pattern? Share your thoughts and experiences in the comments!

AD

Written by Anh Dojo

Backend developer passionate about building scalable systems and sharing knowledge with the community.