Here’s a list of commonly used React.js functions with short descriptions:
useState: Allows you to add state management to functional components, enabling them to re-render when state changes.
Here’s an example of how to use the useState
hook in a React functional component to add state management and enable the component to re-render when the state changes:
import React, { useState } from 'react'; function Counter() { // Declare a state variable 'count' and a function 'setCount' to update it const [count, setCount] = useState(0); // Define a function to increment the count when a button is clicked const handleIncrement = () => { setCount(count + 1); // Update the 'count' state }; return ( <div> <h1>Counter App</h1> <p>Count: {count}</p> <button onClick={handleIncrement}>Increment</button> </div> ); } export default Counter;
In this example:
- We import
useState
from React to use it in our functional component. - Inside the
Counter
component, we use theuseState
hook to declare a state variable calledcount
and a function calledsetCount
to update that state variable. We initialize thecount
state with an initial value of0
. - We render the current value of
count
inside a<p>
element. - We also render a button labeled “Increment,” and when this button is clicked, the
handleIncrement
function is called. Inside this function, we usesetCount
to update thecount
state by incrementing it by 1. - When the state changes due to the button click, React automatically re-renders the component with the updated state value, and you can see the new value displayed in the
<p>
element.
So, useState
allows you to add and manage state within functional components, making it easier to handle data that can change over time and trigger component re-renders when the state changes.
useEffect: Used for side effects in functional components, such as data fetching, DOM manipulation, or subscribing to events.
Here’s an example of how to use the useEffect
hook in a React functional component to handle side effects, such as data fetching:
import React, { useState, useEffect } from 'react'; function DataFetchingExample() { const [data, setData] = useState([]); // State to store fetched data const [loading, setLoading] = useState(true); // State to track loading status useEffect(() => { // Simulate fetching data from an API after 2 seconds setTimeout(() => { // Sample data for demonstration const sampleData = [ { id: 1, name: 'Item 1' }, { id: 2, name: 'Item 2' }, { id: 3, name: 'Item 3' }, ]; setData(sampleData); setLoading(false); // Set loading to false when data is fetched }, 2000); // Simulate a 2-second delay }, []); // Empty dependency array means this effect runs once, similar to componentDidMount return ( <div> <h1>Data Fetching Example</h1> {loading ? ( <p>Loading...</p> ) : ( <ul> {data.map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul> )} </div> ); } export default DataFetchingExample;
In this example:
- We import
useState
anduseEffect
from React to use them in our functional component. - Inside the
DataFetchingExample
component, we declare two state variables:data
to store the fetched data andloading
to track the loading status. - We use the
useEffect
hook to handle the data fetching side effect. Inside the effect function, we simulate fetching data from an API after a 2-second delay usingsetTimeout
. Once the data is fetched (simulated), we update thedata
state with the fetched data and setloading
tofalse
to indicate that the loading is complete. - We use conditional rendering to display either a “Loading…” message while the data is being fetched or a list of items once the data is available.
- The effect is set to run once when the component mounts, thanks to the empty dependency array (
[]
). This behavior is similar tocomponentDidMount
in class components.
useEffect
is versatile and can be used for various side effects, including data fetching, DOM manipulation, and event subscriptions, making it a powerful tool for handling side effects in functional components.
Here are examples of how to use the useEffect
hook for DOM manipulation and event subscriptions in React functional components:
DOM Manipulation
In this example, we’ll use useEffect
to change the background color of a component when it mounts:
import React, { useState, useEffect } from 'react'; function DOMManipulationExample() { const [color, setColor] = useState('white'); useEffect(() => { // Change the background color to green when the component mounts document.body.style.backgroundColor = 'green'; // Revert the background color to white when the component unmounts return () => { document.body.style.backgroundColor = 'white'; }; }, []); // Empty dependency array to run only on component mount const changeColor = () => { // Change the background color to a random color when the button is clicked const randomColor = `#${Math.floor(Math.random() * 16777215).toString(16)}`; setColor(randomColor); }; return ( <div> <h1>DOM Manipulation Example</h1> <p>Click the button to change the background color:</p> <button onClick={changeColor}>Change Color</button> </div> ); } export default DOMManipulationExample;
- The
useEffect
hook now sets the initial background color to'green'
when the component mounts. - When you click the “Change Color” button, it still generates a random color using the
changeColor
function and updates thecolor
state, but this color change is unrelated to the background color set inuseEffect
. The background color set byuseEffect
will remain'green'
until the component is unmounted.
Event Subscription
In this example, we’ll use useEffect
to subscribe to a window resize event:
import React, { useState, useEffect } from 'react'; function EventSubscriptionExample() { const [windowSize, setWindowSize] = useState({ width: window.innerWidth, height: window.innerHeight }); useEffect(() => { // Function to update the windowSize state with the current window dimensions const updateWindowSize = () => { setWindowSize({ width: window.innerWidth, height: window.innerHeight }); }; // Subscribe to the window resize event window.addEventListener('resize', updateWindowSize); // Unsubscribe from the window resize event when the component unmounts return () => { window.removeEventListener('resize', updateWindowSize); }; }, []); return ( <div> <h1>Event Subscription Example</h1> <p>Window Dimensions:</p> <p>Width: {windowSize.width}px</p> <p>Height: {windowSize.height}px</p> </div> ); } export default EventSubscriptionExample;
In this example:
- We use the
useState
hook to manage thewindowSize
state, which stores the current width and height of the window. - Inside the
useEffect
hook, we define anupdateWindowSize
function that updates thewindowSize
state with the current window dimensions whenever the window is resized. - We subscribe to the window resize event using
addEventListener
and callupdateWindowSize
whenever the event occurs. - We also return a cleanup function in the effect to unsubscribe from the window resize event when the component unmounts. This prevents memory leaks.
- The component displays the current window dimensions, and they will automatically update whenever the window is resized.
These examples demonstrate how useEffect
can be used for both DOM manipulation and event subscriptions within React functional components.
useContext: Accesses the context of a parent component, allowing you to pass data down the component tree without manually passing props.
Here’s an example of how to use the useContext
hook in React to access the context of a parent component. This allows you to pass data down the component tree without manually passing props:
import React, { createContext, useContext } from 'react'; // Step 1: Create a context const UserContext = createContext(); // Step 2: Create a parent component that provides the context value function UserProvider({ children }) { const user = { name: 'John', age: 30 }; return ( <UserContext.Provider value={user}> {children} </UserContext.Provider> ); } // Step 3: Create a child component that consumes the context function UserInfo() { const user = useContext(UserContext); return ( <div> <h1>User Information</h1> <p>Name: {user.name}</p> <p>Age: {user.age}</p> </div> ); } function App() { return ( <UserProvider> <div> <h1>App Component</h1> <UserInfo /> </div> </UserProvider> ); } export default App;
In this example:
- We create a
UserContext
usingcreateContext
. This context will be used to pass user data down the component tree. - We create a
UserProvider
component that wraps its children withUserContext.Provider
. InsideUserProvider
, we define theuser
object containing user information, and we provide it as the value of the context. This way, any component within theUserProvider
tree can access theuser
data via the context. - We create a
UserInfo
component, which uses theuseContext
hook to access theUserContext
. It extracts theuser
data from the context and renders it. - In the
App
component, we wrap our content withUserProvider
. This ensures that theUserInfo
component, which is a child ofApp
, can access the user data provided byUserProvider
.
When you run this example, the UserInfo
component can access the user data without explicitly passing it as props, thanks to the useContext
hook and the UserContext.Provider
in the component hierarchy. This is a powerful way to share data across components without prop drilling.
useReducer: Provides a more controlled way to manage state by using reducers, typically for more complex state updates.
Here’s an example of how to use the useReducer
hook in React to manage state in a more controlled way using reducers. This is typically used for more complex state updates:
import React, { useReducer } from 'react'; // Step 1: Define a reducer function const reducer = (state, action) => { switch (action.type) { case 'INCREMENT': return { count: state.count + 1 }; case 'DECREMENT': return { count: state.count - 1 }; case 'RESET': return { count: 0 }; default: return state; } }; // Step 2: Create an initial state const initialState = { count: 0 }; // Step 3: Create a component that uses useReducer function Counter() { // Use useReducer with the reducer and initial state const [state, dispatch] = useReducer(reducer, initialState); return ( <div> <h1>Counter App using useReducer</h1> <p>Count: {state.count}</p> <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button> <button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button> <button onClick={() => dispatch({ type: 'RESET' })}>Reset</button> </div> ); } export default Counter;
In this example:
- We define a
reducer
function that takes two parameters:state
andaction
. Thereducer
is responsible for handling state updates based on theaction
type. - We create an initial state
initialState
, which contains an initial value for thecount
property. - Inside the
Counter
component, we use theuseReducer
hook to manage state. We pass thereducer
function andinitialState
as arguments touseReducer
, which returns the current state and adispatch
function. - We render the current
count
from the state and provide buttons to increment, decrement, and reset the count. When the buttons are clicked, we dispatch actions to the reducer, specifying the action type (‘INCREMENT’, ‘DECREMENT’, or ‘RESET’). - The
reducer
function processes these actions and returns a new state, which is then used to update the component’s UI.
useReducer
is useful for managing complex state updates and is often preferred over useState
when the state logic becomes more involved, or when you need to encapsulate state updates in a predictable manner.
useRef: Creates a mutable ref object that can be used to access and manipulate a DOM element or to persist values between renders without causing re-renders.
Here’s an example of how to use the useRef
hook in React to create a mutable ref object that can be used to access and manipulate a DOM element or persist values between renders without causing re-renders:
import React, { useRef, useEffect } from 'react'; function InputWithFocus() { // Create a ref using useRef const inputRef = useRef(null); // Function to focus the input element when the component mounts useEffect(() => { if (inputRef.current) { inputRef.current.focus(); } }, []); return ( <div> <h1>Input with Focus using useRef</h1> <input ref={inputRef} type="text" placeholder="Enter text" /> </div> ); } export default InputWithFocus;
In this example:
- We import
useRef
from React to use it in our functional component. - Inside the
InputWithFocus
component, we create a mutable ref calledinputRef
usinguseRef(null)
. - We use the
useEffect
hook to focus the input element when the component mounts. TheinputRef.current
allows us to access the actual DOM element and call the.focus()
method on it. - The
useEffect
hook has an empty dependency array[]
, which means it runs once when the component mounts, similar tocomponentDidMount
in class components. - We render an input element and attach the
inputRef
to it using theref
attribute. This allows us to access and manipulate the input element directly without causing re-renders.
When you use useRef
, you can access and modify the DOM element associated with the ref (inputRef.current
in this case) directly, making it useful for various purposes such as focusing elements, working with third-party libraries, or persisting values between renders without causing re-renders.
In React, “persisting values between renders without causing re-renders” refers to the ability to store data or values in a way that survives component re-renders without triggering additional re-renders when the data changes. This can be accomplished using techniques like using the useRef
hook, memoization, or other state management mechanisms.
Here’s a breakdown of what this means:
- Persisting Values Between Renders: When a component re-renders, its state and local variables typically reset to their initial values unless managed differently. However, in some cases, you want to store values that should persist between renders. This could be data fetched from an API, a reference to a DOM element, or any other data that should remain consistent across renders.
- Without Causing Re-renders: In React, when state or props change, a component re-renders. If you store values in a way that triggers a re-render every time the value changes, it can lead to unnecessary re-renders and performance issues. Therefore, it’s often desirable to store such values in a way that doesn’t trigger re-renders when the value is updated.
For example, when you use the useState
hook to manage state, updating the state causes a re-render. But when you use the useRef
hook, updates to the ref don’t trigger re-renders. This makes useRef
a suitable choice for persisting values between renders without causing unnecessary re-renders.
Here’s a simple example to illustrate this concept using useRef
:
import React, { useState, useRef, useEffect } from 'react'; function Counter() { const [count, setCount] = useState(0); const countRef = useRef(0); useEffect(() => { // This effect runs after every render countRef.current = count; // Persist the value in a ref }, [count]); const increment = () => { setCount(count + 1); // This triggers a re-render }; return ( <div> <h1>Counter</h1> <p>Count: {count}</p> <p>Previous Count: {countRef.current}</p> <button onClick={increment}>Increment</button> </div> ); } export default Counter;
In this example, count
is stored in state using useState
, causing a re-render when it changes. However, we also use countRef
(created with useRef
) to store the previous count value without triggering additional re-renders. This way, we can persist the previous count between renders without causing unnecessary updates to the component.
useMemo: Memoizes the result of a function, preventing expensive recalculations when dependencies haven’t changed.
Here’s an example of how to use the useMemo
hook in React to memoize the result of a function, preventing expensive recalculations when dependencies haven’t changed:
import React, { useState, useMemo } from 'react'; function FibonacciCalculator({ n }) { // Function to calculate Fibonacci numbers const calculateFibonacci = (num) => { if (num <= 1) return num; return calculateFibonacci(num - 1) + calculateFibonacci(num - 2); }; // Use useMemo to memoize the result of the calculation const fibonacciResult = useMemo(() => calculateFibonacci(n), [n]); return ( <div> <h1>Fibonacci Calculator</h1> <p>Fibonacci number at index {n}: {fibonacciResult}</p> </div> ); } function App() { const [n, setN] = useState(10); const handleInputChange = (e) => { setN(parseInt(e.target.value, 10)); }; return ( <div> <h1>App</h1> <input type="number" placeholder="Enter a number" value={n} onChange={handleInputChange} /> <FibonacciCalculator n={n} /> </div> ); } export default App;
In this example:
- We have a
FibonacciCalculator
component that calculates Fibonacci numbers. ThecalculateFibonacci
function is used for this purpose. - We use the
useMemo
hook to memoize the result of thecalculateFibonacci
function. The memoization occurs based on then
dependency provided in the dependency array[n]
. This means that thecalculateFibonacci
function will only be recomputed when then
value changes. - In the
App
component, there’s an input field where you can enter a number (n
), which represents the index of the Fibonacci number you want to calculate. - When you enter a new number, the
handleInputChange
function updates then
state, causing theFibonacciCalculator
component to recalculate the Fibonacci number at that index.
Thanks to useMemo
, the expensive Fibonacci calculation is only performed when the n
value changes. If you enter the same n
value again, the previously computed result is reused, preventing unnecessary recalculations. This is particularly useful for optimizing the performance of complex computations in your React components.
useCallback: Memoizes a callback function, useful when passing functions as props to child components to prevent unnecessary re-renders.
Here’s an example of how to use the useCallback
hook in React to memoize a callback function. This is useful when passing functions as props to child components to prevent unnecessary re-renders:
import React, { useState, useCallback } from 'react'; function ChildComponent({ onClick }) { return ( <div> <h2>Child Component</h2> <button onClick={onClick}>Click Me</button> </div> ); } function ParentComponent() { const [count, setCount] = useState(0); // Define a callback function using useCallback const handleClick = useCallback(() => { setCount(count + 1); }, [count]); return ( <div> <h1>Parent Component</h1> <p>Count: {count}</p> <ChildComponent onClick={handleClick} /> </div> ); } export default ParentComponent;
In this example:
- We have a
ChildComponent
that receives a callback functiononClick
as a prop. This function is called when a button in the child component is clicked. - In the
ParentComponent
, we use theuseState
hook to manage acount
state. - We define a callback function
handleClick
using theuseCallback
hook. This function increments thecount
state by 1 when called. - The
useCallback
hook memoizes thehandleClick
function, and its dependencies are specified as[count]
. This means that thehandleClick
function is recreated only when thecount
state changes. This prevents unnecessary re-creation of the function during each render of theParentComponent
. - The
handleClick
function is passed as a prop to theChildComponent
, which can then call it when the button is clicked.
By using useCallback
, you ensure that the callback function passed to child components is stable and won’t cause unnecessary re-renders when the parent component re-renders for reasons unrelated to the callback function. This optimization can be especially helpful in larger applications to improve performance.
useState Context: A custom hook that combines useState
and useContext
to simplify state management within a context.
Here’s an example of how to use a custom hook that combines useState
and useContext
to simplify state management within a context:
import React, { useState, useContext, createContext } from 'react'; // Step 1: Create a context to provide and consume the state const MyContext = createContext(); // Step 2: Create a custom hook that uses useState and useContext function useMyContext() { const context = useContext(MyContext); if (!context) { throw new Error('useMyContext must be used within a MyContextProvider'); } return context; } // Step 3: Create a provider component that uses useState to manage state function MyContextProvider({ children }) { const [count, setCount] = useState(0); const increment = () => { setCount(count + 1); }; const decrement = () => { setCount(count - 1); }; return ( <MyContext.Provider value={{ count, increment, decrement }}> {children} </MyContext.Provider> ); } // Step 4: Use the custom hook in your components function Counter() { const { count, increment, decrement } = useMyContext(); return ( <div> <h1>Counter</h1> <p>Count: {count}</p> <button onClick={increment}>Increment</button> <button onClick={decrement}>Decrement</button> </div> ); } function App() { return ( <MyContextProvider> <Counter /> </MyContextProvider> ); } export default App;
In this example, we create a custom hook useMyContext
that combines useState
and useContext
to simplify state management within a context. Here’s how it works:
- We create a context called
MyContext
usingcreateContext
. - We create a custom hook
useMyContext
that usesuseContext
to access the context’s value. It throws an error if used outside of aMyContextProvider
. - We create a
MyContextProvider
component that usesuseState
to manage thecount
state. It provides thecount
,increment
, anddecrement
functions through the context’s value. - We use the
useMyContext
custom hook in theCounter
component to access the state and functions provided by the context. - Finally, in the
App
component, we wrap theCounter
component with theMyContextProvider
to make the context available to it.
Now, the Counter
component can easily manage and display the count state, and the MyContextProvider
simplifies state management within the context.
useHistory: Provides access to the browser’s navigation history and allows you to programmatically navigate between pages in a single-page application.
Here’s an example of how to use useHistory
to programmatically navigate between pages in a single-page React application:
import React from 'react'; import { useHistory } from 'react-router-dom'; function Home() { const history = useHistory(); const navigateToAbout = () => { // Programmatically navigate to the '/about' route history.push('/about'); }; return ( <div> <h1>Home</h1> <button onClick={navigateToAbout}>Go to About</button> </div> ); } function About() { const history = useHistory(); const navigateBack = () => { // Programmatically navigate back to the previous page history.goBack(); }; return ( <div> <h1>About Us</h1> <button onClick={navigateBack}>Go Back</button> </div> ); } function App() { return ( <div> <Home /> <About /> </div> ); } export default App;
In this example, we have three components: Home
, About
, and App
. We’re using the useHistory
hook from react-router-dom
to access the browser’s navigation history and navigate between pages programmatically.
- In the
Home
component, we import and useuseHistory
to get access to the history object. When the “Go to About” button is clicked, we callhistory.push('/about')
to navigate to the ‘/about’ route, effectively rendering theAbout
component. - In the
About
component, we also useuseHistory
to get the history object. When the “Go Back” button is clicked, we callhistory.goBack()
to navigate back to the previous page, which takes us back to theHome
component. - Finally, we render both the
Home
andAbout
components within theApp
component.
With useHistory
, you can easily manage navigation between pages in a single-page React application, making it convenient for building complex user interfaces and workflows.
useLocation: Returns the current URL location, enabling you to access and react to changes in the browser’s location.
Here’s an example of how to use the useLocation
hook to access and react to changes in the browser’s location in a React application:
import React from 'react'; import { useLocation } from 'react-router-dom'; function CurrentLocation() { // Use the useLocation hook to access the current URL location const location = useLocation(); return ( <div> <h1>Current Location</h1> <p>Current Pathname: {location.pathname}</p> <p>Current Search: {location.search}</p> <p>Current Hash: {location.hash}</p> </div> ); } function App() { return ( <div> <h1>React Router Example</h1> <CurrentLocation /> </div> ); } export default App;
In this example, we’re using the useLocation
hook from react-router-dom
to access the current URL location. The useLocation
hook returns an object that contains information about the current URL, including pathname
, search
, and hash
.
- The
CurrentLocation
component uses theuseLocation
hook to get the current location object. - It then displays the current
pathname
,search
, andhash
in the component’s output. - In the
App
component, we render theCurrentLocation
component to demonstrate how to access and display the current URL location.
With the useLocation
hook, you can easily access and react to changes in the browser’s location, making it useful for building navigation menus, breadcrumbs, or any component that needs to respond to changes in the URL.
useParams: Extracts parameters from the URL, often used with React Router to access route-specific data.
Here’s an example of how to use the useParams
hook from react-router-dom
to extract parameters from the URL in a React application:
Assuming you have a route like this in your React Router configuration:
<Route path="/user/:userId"> <UserProfile /> </Route>
Now, let’s create the UserProfile
component:
import React from 'react'; import { useParams } from 'react-router-dom'; function UserProfile() { // Use the useParams hook to extract the 'userId' parameter from the URL const { userId } = useParams(); return ( <div> <h1>User Profile</h1> <p>User ID: {userId}</p> </div> ); } function App() { return ( <div> <h1>React Router Example</h1> <UserProfile /> </div> ); } export default App;
In this example:
- We have a route defined using React Router where
:userId
is a dynamic parameter in the URL. - In the
UserProfile
component, we use theuseParams
hook to extract theuserId
parameter from the URL. The hook automatically provides us with the parameter value. - We display the extracted
userId
parameter in the component’s output. - In the
App
component, we render theUserProfile
component to demonstrate how to access and use route-specific parameters.
With the useParams
hook, you can easily access and utilize route parameters in your React application. This is useful for building dynamic and personalized views based on the URL.
useForm: Custom hook for managing form state and handling form submissions more easily.
Here’s an example of how to create and use a custom useForm
hook for managing form state and handling form submissions more easily in a React application:
import React, { useState } from 'react'; // Custom useForm hook for managing form state function useForm(initialValues = {}) { const [values, setValues] = useState(initialValues); // Function to update form field values const handleChange = (e) => { const { name, value } = e.target; setValues({ ...values, [name]: value, }); }; // Function to reset form fields to initial values const resetForm = () => { setValues(initialValues); }; return { values, handleChange, resetForm }; } function MyForm() { // Initialize form state using the useForm hook const { values, handleChange, resetForm } = useForm({ firstName: '', lastName: '', email: '', }); // Function to handle form submission const handleSubmit = (e) => { e.preventDefault(); // Perform actions with form data, e.g., send it to a server console.log('Form submitted with data:', values); // Reset the form resetForm(); }; return ( <form onSubmit={handleSubmit}> <div> <label> First Name: <input type="text" name="firstName" value={values.firstName} onChange={handleChange} /> </label> </div> <div> <label> Last Name: <input type="text" name="lastName" value={values.lastName} onChange={handleChange} /> </label> </div> <div> <label> Email: <input type="email" name="email" value={values.email} onChange={handleChange} /> </label> </div> <div> <button type="submit">Submit</button> </div> </form> ); } function App() { return ( <div> <h1>Custom useForm Hook Example</h1> <MyForm /> </div> ); } export default App;
In this example:
- We create a custom
useForm
hook that initializes and manages the form’s state using theuseState
hook. It also provides functions for handling form field changes and resetting the form to its initial state. - In the
MyForm
component, we initialize the form state using theuseForm
hook, specifying the initial field values as an object. - We define an
handleChange
function to update the form field values as the user types. - The
handleSubmit
function is called when the form is submitted. It logs the form data to the console (you can replace this with your form submission logic) and resets the form to its initial state using theresetForm
function. - The form fields are controlled components, meaning their values are derived from the
values
object in the form state. - Finally, in the
App
component, we render theMyForm
component to demonstrate how to use the customuseForm
hook for managing form state and handling form submissions more easily.
useLayoutEffect: Similar to useEffect
, but fires synchronously after all DOM mutations. Use with caution as it can cause performance issues.
Certainly! Here’s an example of how to use the useLayoutEffect
hook, which is similar to useEffect
but fires synchronously after all DOM mutations. Please note that you should use it with caution, as it can impact performance if not used carefully.
import React, { useState, useEffect, useLayoutEffect } from 'react'; function LayoutEffectExample() { const [count, setCount] = useState(0); // useEffect example (fires asynchronously) useEffect(() => { console.log(`useEffect: Count is ${count}`); }, [count]); // useLayoutEffect example (fires synchronously) useLayoutEffect(() => { console.log(`useLayoutEffect: Count is ${count}`); }, [count]); const incrementCount = () => { setCount(count + 1); }; return ( <div> <h1>useLayoutEffect Example</h1> <p>Count: {count}</p> <button onClick={incrementCount}>Increment</button> </div> ); } function App() { return ( <div> <h1>React useLayoutEffect Example</h1> <LayoutEffectExample /> </div> ); } export default App;
In this example:
- We have a
LayoutEffectExample
component that maintains acount
state usinguseState
. - We use both
useEffect
anduseLayoutEffect
to demonstrate the difference in behavior. Both hooks log the current value ofcount
when it changes. - The
incrementCount
function allows us to increment thecount
state when the “Increment” button is clicked. - In the component’s render, we display the current count and a button to increment it.
When you run this code, you’ll notice the following behavior:
useEffect
logs the count value asynchronously after the DOM update. It might not always reflect the latest value immediately after the button click.useLayoutEffect
logs the count value synchronously after the DOM update, which means it runs before the browser has a chance to paint the changes. This can potentially lead to a more accurate reflection of the state but can also cause performance issues, especially if the code insideuseLayoutEffect
is computationally expensive.
You should use useLayoutEffect
when you need to make changes to the DOM that must be reflected immediately and can’t wait for the next render cycle. However, be cautious and use it sparingly to avoid performance problems. In most cases, useEffect
is sufficient for handling side effects.
useDebugValue: Adds debug information to custom hooks, making it easier to inspect their values and behavior in development tools.
Here’s an example of how to use the useDebugValue
hook to add debug information to a custom hook, making it easier to inspect its values and behavior in development tools:
import React, { useState, useEffect, useDebugValue } from 'react'; // Custom hook that fetches data and provides a loading state function useDataLoader(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { fetch(url) .then((response) => response.json()) .then((result) => { setData(result); setLoading(false); }) .catch((error) => { console.error('Error fetching data:', error); setLoading(false); }); }, [url]); // Use useDebugValue to add debug information useDebugValue(loading ? 'Loading...' : `Data: ${JSON.stringify(data)}`); return { data, loading }; } function DataLoader() { // Use the custom hook to fetch data const { data, loading } = useDataLoader('https://jsonplaceholder.typicode.com/posts/1'); return ( <div> <h1>Data Loader</h1> {loading ? ( <p>Loading data...</p> ) : ( <pre>{JSON.stringify(data, null, 2)}</pre> )} </div> ); } function App() { return ( <div> <h1>useDebugValue Example</h1> <DataLoader /> </div> ); } export default App;
In this example:
- We create a custom hook called
useDataLoader
that fetches data from a specified URL and provides a loading state (loading
) along with the fetched data (data
). - Inside the
useDataLoader
custom hook, we useuseDebugValue
to add debug information. Whenloading
istrue
, it displays “Loading…”; otherwise, it displays the serialized JSON representation of thedata
. - The
DataLoader
component uses theuseDataLoader
custom hook to fetch and display data. It renders a loading message whileloading
istrue
and shows the fetched data when it’s available. - In the
App
component, we render theDataLoader
component to demonstrate howuseDebugValue
can provide debug information.
When you use the React DevTools in your browser to inspect the DataLoader
component, you’ll see the custom debug information provided by useDebugValue
. This can be extremely helpful for understanding the behavior of custom hooks and debugging them effectively during development.
useImperativeHandle: Customizes the instance value that is exposed when using React.forwardRef
, allowing you to control what methods or properties are accessible from parent components.
Here’s an example of how to use the useImperativeHandle
hook to customize the instance value that is exposed when using React.forwardRef
. This allows you to control what methods or properties are accessible from parent component
import React, { useRef, useImperativeHandle, forwardRef } from 'react'; // Child component that exposes a method via useImperativeHandle const ChildComponent = forwardRef((props, ref) => { const someInternalValue = 'This is an internal value'; // Create a ref to hold the exposed instance value const exposedInstance = useRef(); // Define the method that will be exposed to the parent const greet = () => { console.log('Hello from ChildComponent!'); }; // Use useImperativeHandle to customize the exposed instance value useImperativeHandle(ref, () => ({ greet, someInternalValue, })); return <div>Child Component</div>; }); // Parent component that uses the child component function ParentComponent() { const childRef = useRef(); const handleGreetButtonClick = () => { // Call the exposed method from the child component childRef.current.greet(); }; return ( <div> <h1>Parent Component</h1> <button onClick={handleGreetButtonClick}>Greet Child</button> <ChildComponent ref={childRef} /> </div> ); } function App() { return ( <div> <h1>useImperativeHandle Example</h1> <ParentComponent /> </div> ); } export default App;
In this example:
- We have a
ChildComponent
that usesReact.forwardRef
to allow a parent component to access its methods and properties via aref
. - Inside the
ChildComponent
, we define an internal value (someInternalValue
) and a method (greet
) that we want to expose to the parent component. - We create a ref (
exposedInstance
) to hold the instance value that we want to expose. - We use the
useImperativeHandle
hook to customize the exposed instance value. The hook takes two arguments: theref
and a function that returns an object with the properties and methods we want to expose. - In the
ParentComponent
, we create a ref (childRef
) and pass it to theChildComponent
. When the “Greet Child” button is clicked, we call thegreet
method from the child component, demonstrating how we can control what methods are accessible from the parent component.
This example illustrates how useImperativeHandle
can be used to customize the interface between child and parent components, allowing you to expose specific functionality while encapsulating the implementation details within the child component.
useErrorBoundary: Creates an error boundary component that can catch and handle errors in its child components, preventing the entire app from crashing.
useEffectAfterRender: A custom hook that lets you perform actions after the component has rendered and the DOM is updated, useful for integrating with third-party libraries or animations.
These are some of the essential React.js functions and custom hooks that developers frequently use to build dynamic and interactive web applications.