Introduction
In this chapter, we will explore React Hooks, a feature that allows you to use state and other React features in functional components. Hooks were introduced in React 16.8 to provide a way to use state and lifecycle methods without writing class components. We will cover the most commonly used hooks, such as useState, useEffect, and useContext, with practical examples to demonstrate their usage.
Table of Contents
- What are React Hooks?
- Using
useState- Example: Counter
- Using
useEffect- Example: Fetching Data
- Using
useContext- Example: Theme Context
- Custom Hooks
- Example: useLocalStorage Hook
- Conclusion
What are React Hooks?
React Hooks allow you to use state and other React features in functional components. They enable you to manage component state, handle side effects, and access context in a more concise and readable way. Hooks follow a set of rules, such as only calling hooks at the top level of your component or custom hook and only calling them from React function components or custom hooks.
Using useState
The useState hook lets you add state to functional components. It returns an array with the current state value and a function to update that state.
Example: Counter
- Create a Counter Component: In the
srcdirectory, create a new file namedCounter.js. - Define the Counter Component: Add the following code to
Counter.js:// src/Counter.js import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); return ( <div className="container mt-5"> <h2>Counter</h2> <p>Current Count: {count}</p> <button className="btn btn-primary" onClick={() => setCount(count + 1)}> Increment </button> </div> ); } export default Counter;Explanation:
- We use the
useStatehook to create acountstate variable and asetCountfunction to update it. - The button calls
setCountwith the current count incremented by 1 each time it is clicked.
- We use the
- Use the Counter Component in
App.js: Opensrc/App.jsand import theCountercomponent:// src/App.js import React from 'react'; import Counter from './Counter'; function App() { return ( <div> <Counter /> </div> ); } export default App; - Save and View Changes: Save the files and go to your browser. You should see a counter that increments when you click the button.
Using useEffect
The useEffect hook lets you perform side effects in functional components. It runs after the first render and after every update, but you can control when it runs by specifying dependencies.
Example: Fetching Data
- Create a DataFetching Component: In the
srcdirectory, create a new file namedDataFetching.js. - Define the DataFetching Component: Add the following code to
DataFetching.js:// src/DataFetching.js import React, { useState, useEffect } from 'react'; function DataFetching() { const [data, setData] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { fetch('https://jsonplaceholder.typicode.com/posts') .then((response) => response.json()) .then((data) => { setData(data); setLoading(false); }); }, []); return ( <div className="container mt-5"> <h2>Data Fetching</h2> {loading ? ( <p>Loading...</p> ) : ( <ul> {data.slice(0, 5).map((item) => ( <li key={item.id}>{item.title}</li> ))} </ul> )} </div> ); } export default DataFetching;Explanation:
- We use the
useStatehook to createdataandloadingstate variables. - We use the
useEffecthook to fetch data from an API when the component mounts. The empty array[]as the second argument ensures the effect runs only once. - We display a loading message while the data is being fetched and render the data once it is loaded.
- We use the
- Use the DataFetching Component in
App.js: Opensrc/App.jsand import theDataFetchingcomponent:// src/App.js import React from 'react'; import Counter from './Counter'; import DataFetching from './DataFetching'; function App() { return ( <div> <Counter /> <DataFetching /> </div> ); } export default App; - Save and View Changes: Save the files and go to your browser. You should see a list of data fetched from the API.
Using useContext
The useContext hook lets you access context values in functional components. It simplifies the process of consuming context compared to the Context.Consumer component.
Example: Theme Context
- Create a Theme Context: In the
srcdirectory, create a new file namedThemeContext.js. - Define the Theme Context: Add the following code to
ThemeContext.js:// src/ThemeContext.js import React, { createContext, useState } from 'react'; const ThemeContext = createContext(); export const ThemeProvider = ({ children }) => { const [theme, setTheme] = useState('light'); return ( <ThemeContext.Provider value={{ theme, setTheme }}> {children} </ThemeContext.Provider> ); }; export default ThemeContext;Explanation:
- We create a
ThemeContextusingcreateContext. - The
ThemeProvidercomponent manages thethemestate and provides it to the component tree.
- We create a
- Create a ThemedComponent: In the
srcdirectory, create a new file namedThemedComponent.js. - Define the ThemedComponent: Add the following code to
ThemedComponent.js:// src/ThemedComponent.js import React, { useContext } from 'react'; import ThemeContext from './ThemeContext'; function ThemedComponent() { const { theme, setTheme } = useContext(ThemeContext); return ( <div className={`container mt-5 ${theme === 'dark' ? 'bg-dark text-white' : 'bg-light text-dark'}`}> <h2>Themed Component</h2> <p>Current theme: {theme}</p> <button className="btn btn-secondary" onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}> Toggle Theme </button> </div> ); } export default ThemedComponent;Explanation:
- We use the
useContexthook to access thethemevalue andsetThemefunction from theThemeContext. - The button toggles the theme between light and dark.
- We use the
- Use the ThemeProvider in
App.js: Opensrc/App.jsand import theThemeProviderandThemedComponentcomponents:// src/App.js import React from 'react'; import Counter from './Counter'; import DataFetching from './DataFetching'; import { ThemeProvider } from './ThemeContext'; import ThemedComponent from './ThemedComponent'; function App() { return ( <ThemeProvider> <Counter /> <DataFetching /> <ThemedComponent /> </ThemeProvider> ); } export default App; - Save and View Changes: Save the files and go to your browser. You should see the themed component with a button to toggle the theme.
Custom Hooks
Custom hooks allow you to extract and reuse logic in functional components. They are JavaScript functions that start with the word “use” and can call other hooks.
Example: useLocalStorage Hook
- Create a Custom Hook: In the
srcdirectory, create a new file nameduseLocalStorage.js. - Define the Custom Hook: Add the following code to
useLocalStorage.js:// src/useLocalStorage.js import { useState } from 'react'; function useLocalStorage(key, initialValue) { const [storedValue, setStoredValue] = useState(() => { try { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch (error) { console.log(error); return initialValue; } }); const setValue = (value) => { try { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); window.localStorage.setItem(key, JSON.stringify(valueToStore)); } catch (error) { console.log(error); } }; return [storedValue, setValue]; } export default useLocalStorage;Explanation:
- The
useLocalStoragehook manages state that is synchronized withlocalStorage. - It initializes the state from
localStorageand updateslocalStoragewhenever the state changes.
- The
- Use the Custom Hook: In the
srcdirectory, create a new file namedLocalStorageComponent.js. - Define the LocalStorageComponent: Add the following code to
LocalStorageComponent.js:// src/LocalStorageComponent.js import React from 'react'; import useLocalStorage from './useLocalStorage'; function LocalStorageComponent() { const [name, setName] = useLocalStorage('name', ''); return ( <div className="container mt-5"> <h2>Local Storage Hook</h2> <input type="text" className="form-control" value={name} onChange={(e) => setName(e.target.value)} placeholder="Enter your name" /> <p>Your name is: {name}</p> </div> ); } export default LocalStorageComponent;Explanation:
- The
LocalStorageComponentuses theuseLocalStoragehook to manage a name input synchronized withlocalStorage.
- The
- Use the LocalStorageComponent in
App.js: Opensrc/App.jsand import theLocalStorageComponentcomponent:// src/App.js import React from 'react'; import Counter from './Counter'; import DataFetching from './DataFetching'; import { ThemeProvider } from './ThemeContext'; import ThemedComponent from './ThemedComponent'; import LocalStorageComponent from './LocalStorageComponent'; function App() { return ( <ThemeProvider> <Counter /> <DataFetching /> <ThemedComponent /> <LocalStorageComponent /> </ThemeProvider> ); } export default App; - Save and View Changes: Save the files and go to your browser. You should see the Local Storage component with an input field synchronized with
localStorage.
Conclusion
In this chapter, we explored React Hooks and how they allow you to use state and other React features in functional components. We covered the most commonly used hooks, such as useState, useEffect, and useContext, with practical examples. We also demonstrated how to create custom hooks to extract and reuse logic in your applications. Understanding and using hooks can help you write cleaner and more efficient React components.