Skip to main content

Working with React Hooks

1. Using useState Hook

Property Description Example
useState(initialValue) Initializes a state variable with the provided initial value const [count, setCount] = useState(0);
setCount(newValue) Updates the state value to newValue setCount(count + 1);

Example: Counter Component

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
Note: The useState hook returns an array with two elements: the current state value and a function to update it.

2. Using useEffect Hook

Property Description Usage
useEffect Hook to perform side effects in functional components useEffect(() => { /* effect */ }, [dependencies]);

Example: Basic useEffect usage

import React, { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    console.log("Component mounted or re-rendered");
  });

  return <div>Hello World</div>;
}

Example: useEffect with cleanup

import React, { useEffect } from 'react';

function Timer() {
  useEffect(() => {
    const interval = setInterval(() => {
      console.log("Timer tick");
    }, 1000);

    return () => clearInterval(interval); // Cleanup function
  }, []);

  return <div>Timer Component</div>;
}

Example: useEffect with dependencies

import React, { useEffect, useState } from 'react';

function DataFetcher({ userId }) {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch(`/api/user/${userId}`)
      .then(res => res.json())
      .then(setData);
  }, [userId]); // Only re-run if userId changes

  return <div>{data ? data.name : "Loading..."}</div>;
}
Note: The dependency array is optional but recommended to prevent unnecessary re-runs.

3. Using useContext Hook

The useContext hook allows you to access data from a React context directly within a functional component, without needing to use a class component or manually pass props down through multiple levels of components.

Property Description Example
useContext(context) Accepts a context object (created by React.createContext) and returns the current context value for that context. const theme = useContext(ThemeContext);

Example: Using useContext to access theme

import React, { useContext } from 'react';

const ThemeContext = React.createContext();

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return (
    <button style={{ background: theme.background, color: theme.text }}>
      Click me
    </button>
  );
}

function App() {
  return (
    <ThemeContext.Provider value={{ background: '#000', text: '#fff' }}>
      <ThemedButton />
    </ThemeContext.Provider>
  );
}
Note: useContext will always return the value from the nearest parent Provider in the component tree. If no matching context is found, it will return the default value provided when creating the context.

4. Using useRef Hook

Property Description Usage
useRef(initialValue) Creates a mutable ref object whose .current property is initialized to the passed argument const ref = useRef(0);
ref.current Access or modify the value stored in the ref object ref.current = 5;

Example: Managing focus with useRef

import React, &#123; useRef &#125; from 'react';\n\nfunction FocusInput() &#123;\n  const inputRef = useRef(null);\n\n  const focusInput = () => &#123;\n    inputRef.current.focus();\n  &#125;;\n\n  return (&#123;\n    <div>\n      <input ref={inputRef} type="text" />\n      <button onClick={focusInput}>Focus Input</button>\n    </div>\n  );\n&#125;

Example: Storing a timer ID

import React, &#123; useRef, useEffect &#125; from 'react';\n\nfunction Timer() &#123;\n  const timerRef = useRef(null);\n\n  useEffect(() => &#123;\n    timerRef.current = setInterval(() => &#123;\n      console.log('Timer tick');\n    &#125;, 1000);\n\n    return () => clearInterval(timerRef.current);\n  &#125;, []);\n\n  return <div>Timer running...</div>;\n&#125;
Note: useRef does not cause re-renders when its value changes. It's ideal for storing values that don't affect rendering.

5. Using useMemo Hook

Property Description Usage
useMemo Optimizes performance by memoizing expensive calculations const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

Example: Memoizing a Computation

import React, { useMemo } from 'react';

function expensiveCalculation(num) {
  console.log('Computing...');
  return num * 2;
}

function MyComponent({ value }) {
  const memoizedResult = useMemo(() => expensiveCalculation(value), [value]);

  return <div>Result: {memoizedResult}</div>;
}
Note: The useMemo hook prevents unnecessary re-computations when dependencies haven't changed.
Warning: Do not use useMemo for every calculation — only when performance is actually an issue.

6. Using useCallback Hook

Property Description Usage
useCallback Hook to memoize functions const memoizedCallback = useCallback(() => {

Example: Basic useCallback Usage

import React, { useCallback } from 'react';\n\nconst MyComponent = () => {\n  const handleClick = useCallback(() => {\n    console.log('Button clicked');\n  }, []);\n\n  return <button onClick={handleClick}>Click me</button>;\n};
Note: The useCallback hook is useful for optimizing child components that rely on function props.

Key Points

  • useCallback returns a memoized version of the callback.
  • It only changes if one of its dependencies changes.
  • Useful for performance optimization in React components.

7. Creating Custom Hooks

Custom hooks are a powerful way to extract and reuse logic across components in React Native. They follow the same naming convention as built-in hooks (e.g., useMyLogic) and can use other hooks internally.

Hook Name Description Usage
useMyLogic Extracts reusable logic into a custom hook const { data, loading } = useMyLogic();

Example: Custom Hook for Fetching Data

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(setData)
      .finally(() => setLoading(false));
  }, [url]);

  return { data, loading };
}

// Usage in component
const MyComponent = () => {
  const { data, loading } = useFetch('https://api.example.com/data');
  if (loading) return <Text>Loading...</Text>;
  return <Text>{data.title}</Text>;
};
Note: Custom hooks must be called at the top level of a component or another custom hook, never inside conditional blocks or loops.

8. Using useLayoutEffect Hook

The useLayoutEffect hook is a variant of useEffect that fires synchronously after all DOM mutations but before the browser paints. It's primarily used for reading layout information or making DOM measurements that need to be synchronous.

Property Description Notes
useLayoutEffect(callback, deps) Runs a side effect synchronously after DOM updates Same signature as useEffect, but with synchronous execution

Example: Reading DOM Dimensions

import React, { useLayoutEffect, useRef } from 'react';

function MyComponent() {
  const ref = useRef(null);
  const [dimensions, setDimensions] = useState({ width: 0, height: 0 });

  useLayoutEffect(() => {
    const { width, height } = ref.current.getBoundingClientRect();
    setDimensions({ width, height });
  }, []);

  return <div ref={ref}>Dimensions: {dimensions.width} x {dimensions.height}</div>;
}
Note: Unlike useEffect, useLayoutEffect blocks the browser from painting, which can cause performance issues if used improperly. It should only be used when you need to read or measure DOM properties synchronously.

9. Using useImperativeHandle Hook

The useImperativeHandle hook allows a parent component to access the ref of a child component, specifically customizing the instance value that is exposed to the parent.

Parameter Description Notes
ref The ref object passed to the child component. Must be a forwardRefed component.
getSnapshot A function that returns the value to be exposed to the parent. Called during rendering and must be pure.

Example: Custom ref with useImperativeHandle

import React, { forwardRef, useImperativeHandle } from 'react';\n\nconst CustomInput = forwardRef((props, ref) => {\n  useImperativeHandle(ref, () => ({\n    focus: () => {\n      console.log('Input focused');\n    },\n    getValue: () => 'Custom Value'\n  }));\n\n  return <input type="text" />;\n});\n\nexport default CustomInput;

Example: Using ref in parent component

import React, { useRef } from 'react';\nimport CustomInput from './CustomInput';\n\nfunction ParentComponent() {\n  const inputRef = useRef();\n\n  const handleFocus = () => {\n    inputRef.current.focus();\n  };\n\n  return (\n    <>\n      <CustomInput ref={inputRef} />\n      <button onClick={handleFocus}>Focus Input</button>\n    </>\n  );\n}
Note: useImperativeHandle should be used sparingly and only when necessary to maintain a clean component architecture.

10. Understanding Hook Rules and Best Practices

Note: All hooks must be called at the top level of a React function component or custom hook. They cannot be called inside loops, conditions, or nested functions.
Rule Description Example
Top Level Hooks must be called at the top level of a component or custom hook.
function MyComponent() {
  const [state, setState] = useState(0); // ✅ Correct
  useEffect(() => { ... }); // ✅ Correct
}
Conditional Calls Do not call hooks inside conditions or loops.
function MyComponent() {
  if (condition) {
    const [state, setState] = useState(0); // ❌ Incorrect
  }
}
Custom Hooks Custom hooks must start with "use" and can call other hooks.
function useCounter() {
  const [count, setCount] = useState(0);
  return [count, setCount];
}

Best Practices Summary

  • Always call hooks at the top level of your React function components.
  • Use useEffect for side effects and useState for state management.
  • Create custom hooks to encapsulate logic and promote reusability.
  • Follow naming conventions: use prefix for custom hooks.

Was this article helpful?