1. useState

Overview

  • Used for managing state within functional components
  • returns stateful value and a setter function to update the value
  • syntax -
const [state, setState] = useState(initialValue);

Initial State

  • The initial value can be any type
  • Lazy Initialization - If the initial value is expensive, pass a function that returns that value, this function will be run only once during the initial render. If directly the value is passed.
const [count, setCount] = useState(0);
const [state, setState] = useState(() => computeInitialState());

Update State

  • To update the state, call the setter function (setState).
  • This schedules a re-render of the component, and to be noted, update is not immediate.
  • If the new state depends on the previous state, pass a function to setState that takes the previous state as an argument.
setState(newValue);
setState(prevState => prevState + 1);

Preserving the state between the renders

  • useState preserves state between the renders. When the state is updated using setState, the component re-renders, but the updated state is retained across renders.
  • Re-renders do not reset state, unlike regular variables state variables will retain their value even after the component re-renders.

Rules of useState

  • Only call hooks at the top level of react functional components, not inside loops, conditions or nested functions.
  • Only call hooks inside the React Functional components or custom hooks.

2. useEffect

Used to synchronize a component with an external system.

Parameters

  • setup:
    • This is a function where the logic is executed.
    • It can also return a function, which is called cleanup function.
    • After the component is added to the DOM, the setup function is run.
    • After every re-render, first the clean function is called (with old values if provided) and then run the setup function with the changed states.
    • After the component is removed from the DOM, react runs the cleanup function.
  • Optional dependencies:
    • List of all props, states, variables and functions declared in the component function and used in setup function. React compares the changes between renders.
    • If this is not present, effect will run after each re-render of the component.
    • If some value is not reactive and not needed in the dependency array, remove it from the component function to proof its not reactive instead of suppressing the linter.
    • Giving an empty array will not re-run the effect on re-renders.
    • Remove unnecessary function dependency by declaring the function inside the effect setup function.

Syntax

useEffect(() => {
	function createOptions() {
	  return {
		serverUrl: serverUrl,
		roomId: roomId
	  };
	}
 
	const options = createOptions();
	const connection = createConnection(options);
	connection.connect();
	return () => connection.disconnect();
}, [roomId]);

3. useRef Hook

useRef is a React Hook that lets you reference a value that’s not needed for rendering.

Parameters

  • initialValue: The value you want the ref object’s current property to be initially. It can be a value of any type and is ignored after the initial render.

Returns

useRef returns an object with a single property, current

  • current: Initially, it’s set to the initialValue you have passed. You can later set it to something else. If you pass the ref object to React as a ref attribute to a JSX node, React will set its current property.

On the next renders, useRef will return the same object.

Stopwatch Example:

import { useState, useRef, useEffect } from 'react';
 
export default function Stopwatch() {
	const [startTime, setStartTime] = useState(null);
	const [time, setTime] = useState(0);
	const [now, setNow] = useState(null);
	const intervalRef = useRef(null);
 
	useEffect( ()=> {
		if (startTime != null && now != null) {
			  setTime((now - startTime)/1000);
		}
	},[time, now, startTime] );
 
	function handleStart() {
		setStartTime(Date.now());
		setNow(Date.now());
	
		clearInterval(intervalRef.current);
		intervalRef.current = setInterval(() => {
		  setNow(Date.now());
		}, 1000);
	}
 
	function handleStop() {
		clearInterval(intervalRef.current);
	}
  
	return (
		<>
			<h1>Time passed: {time}</h1>
			<button onClick={handleStart}>
				Start
			</button>
			<button onClick={handleStop}>
				Stop
			</button>
		</>
	);
}

By using a ref, you ensure that:

  • store information between re-renders
  • Changing it does not trigger a re-render

Use a ref to manipulate the DOM. React has built-in support for this.

  • declare a ref object with an initial value of null
  • pass your ref object as the ref attribute to the JSX of the DOM node
import { useRef } from 'react';
 
function handleClick() {
	inputRef.current.focus();
}
 
function MyComponent() {
	const inputRef = useRef(null);
	// ...
	
	return <input ref={inputRef} />
}

4. useReducer Hook

This hook is to consolidate states in a component, and updates can be handled outside of the component.

  • Move from setting state to dispatching actions
  • Reducer function to handle the state mutation logic
  • User reducer in the component

Example:

import { useReducer } from 'react';
import AddTask from './AddTask.js';
import TaskList from './TaskList.js';
 
export default function TaskApp() {
  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
 
  function handleAddTask(text) {
    dispatch({
      type: 'added',
      id: nextId++,
      text: text,
    });
  }
 
  function handleChangeTask(task) {
    dispatch({
      type: 'changed',
      task: task,
    });
  }
 
  function handleDeleteTask(taskId) {
    dispatch({
      type: 'deleted',
      id: taskId,
    });
  }
 
  return (
    <>
      <h1>Prague itinerary</h1>
      <AddTask onAddTask={handleAddTask} />
      <TaskList
        tasks={tasks}
        onChangeTask={handleChangeTask}
        onDeleteTask={handleDeleteTask}
      />
    </>
  );
}
 
function tasksReducer(tasks, action) {
  switch (action.type) {
    case 'added': {
      return [
        ...tasks,
        {
          id: action.id,
          text: action.text,
          done: false,
        },
      ];
    }
    case 'changed': {
      return tasks.map((t) => {
        if (t.id === action.task.id) {
          return action.task;
        } else {
          return t;
        }
      });
    }
    case 'deleted': {
      return tasks.filter((t) => t.id !== action.id);
    }
    default: {
      throw Error('Unknown action: ' + action.type);
    }
  }
}
 
let nextId = 3;
const initialTasks = [
  {id: 0, text: 'Visit Kafka Museum', done: true},
  {id: 1, text: 'Watch a puppet show', done: false},
  {id: 2, text: 'Lennon Wall pic', done: false},
];

5. useContext

  • Context lets a component provide some information to the entire tree below it.
  • To pass context:
    1. Create and export it with export const MyContext = createContext(defaultValue).
    2. Pass it to the useContext(MyContext) Hook to read it in any child component, no matter how deep.
    3. Wrap children into <MyContext.Provider value={...}> to provide it from a parent.
  • Context passes through any components in the middle.
  • Before you use context, try passing props or passing JSX as children.

6. useMemo

This hook is used to memoize / cache any object between the renders. It specifically helps to skip re-render of components if the props are not changed. Example:

// In a component where visibleTodos is passed won't re-render as it will send a cached value
// Without useMemo, even if the array is same, still the array is a new object and the component will re-render
const visibleTodos = useMemo(() => {  
	return filterTodos(todos, tab); // Skipped if todos and tab haven't changed  
}, [todos, tab]);
 
// A Component can also be cached using memo
import { memo } from 'react';
 
const List = memo(function List({ items }) {
	// ...
})
 

7. useCallback

This hook is used to memoize / cache any function between the renders. Since same function is actually a new object in JavaScript if created again, caching it can help to skip re-renders if function is not changed. Example:

import { useCallback } from 'react';  
 
function ProductPage({ productId, referrer, theme }) {
	// In components where this handleSubmit is passed can make use of cached value
	const handleSubmit = useCallback((orderDetails) => {
		post('/product/' + productId + '/buy', {  
			referrer,
			orderDetails,
	});
}, [productId, referrer]);  
 
// ...

8. useTransition

9. Custom Hooks