Open In App

React useSyncExternalStore Hook

Last Updated : 11 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

State management is a critical aspect of React applications, and often, developers need to synchronize their application state with an external data store. React’s useSyncExternalStore hook provides a seamless solution to this challenge.

In this article, we’ll explore what the useSyncExternalStore hook is, its benefits, syntax, and internal workings, and provide practical examples of its usage.

What is useSyncExternalStore?

The useSyncExternalStore hook is a custom React hook that facilitates the synchronization of the React component state with an external data store, such as localStorage or sessionStorage. It allows developers to persist and retrieve component state across browser sessions, enabling seamless user experiences and preserving application state.

Syntax of useSyncExternalStore Hook:

const [state, setState] = useSyncExternalStore(key, initialValue);
  • key: A unique identifier used to store and retrieve the state from the external data store.
  • initialValue: The initial value of the state.

Reasons to Use useSyncExternalStore:

  • Persistent State: By synchronizing the state with an external store, developers can ensure that the application state persists even after the browser is refreshed or the user navigates away from the page.
  • Cross-Tab Communication: useSyncExternalStore enables communication between multiple browser tabs or windows by sharing the same state across different instances of the application.
  • Seamless User Experience: With a synchronized state, users can seamlessly resume their interactions with the application without losing their previous state.

Internal Working of useSyncExternalStore Hook:

The useSyncExternalStore hook leverages the useState and useEffect hooks internally to manage state and synchronize it with the external data store. When the component mounts, it retrieves the state from the store using the specified key. Any updates to the state trigger the useEffect hook, which updates the state in the external store.

Steps to Create React Application:

Step 1: Create the React application using the following command.

npx create-react-app useSyncExternalStore
cd useSyncExternalStore

Step 2: To start the application run the following command.

npm start

Folder Structure:

fkir

The updated dependencies in package.json file will look like:

"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}

Example of useSyncExternalStore Hook

Example 1: Counter with Persistent State

Javascript




//App.js
 
import React from 'react';
import useSyncExternalStore
    from './useSyncExternalStore';
 
function Counter() {
    /*
       Using the useSyncExternalStore
       hook to manage the count state
    */
    const [count, setCount] =
        useSyncExternalStore('count', 0);
 
    const increment = () => {
        setCount(prevCount => prevCount + 1);
    };
 
    const decrement = () => {
        setCount(prevCount => prevCount - 1);
    };
 
    return (
        <div>
            <button onClick={decrement}>-</button>
            <span>{count}</span>
            <button onClick={increment}>+</button>
        </div>
    );
}
 
export default Counter;


Javascript




//useSyncExternalStore.js
 
import {
    useState,
    useEffect
} from 'react';
 
// Custom hook for syncing state with external store (localStorage)
function useSyncExternalStore(key, initialValue) {
    const [storedValue, setStoredValue] = useState(() => {
        const item = window.localStorage.getItem(key);
        return item ? JSON.parse(item) : initialValue;
    });
 
    useEffect(() => {
        window.localStorage
            .setItem(key, JSON.stringify(storedValue));
    }, [key, storedValue]);
 
    return [storedValue, setStoredValue];
}
 
export default useSyncExternalStore;


Output: Even after refreshing the count didn’t went back to 0.

Animation1

Example 2: Form Input with Persistent State:

CSS




/* App.css */
 
.form-container {
    max-width: 400px;
    margin: 30px 100px;
}
 
.input-field {
    width: 100%;
    padding: 8px;
    margin-bottom: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
    box-sizing: border-box;
}
 
.submit-button {
    background-color: #4CAF50;
    color: white;
    padding: 10px 20px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}
 
.submit-button:hover {
    background-color: #45a049;
}


Javascript




// App.js
 
import React from 'react';
import useSyncExternalStore
    from './useSyncExternalStore';
import './App.css';
 
function App() {
    const [formData, setFormData] =
        useSyncExternalStore('form_data', {
            name: '',
            email: '',
            message: ''
        });
 
    const handleChange = event => {
        const { name, value } = event.target;
        setFormData(prevData => ({
            ...prevData,
            [name]: value
        }));
    };
 
    const handleSubmit = event => {
        event.preventDefault();
        console.log('Form submitted:', formData);
    };
 
    return (
        <form onSubmit={handleSubmit}
            className="form-container">
            <label>
                Name:
                <input
                    type="text"
                    name="name"
                    value={formData.name}
                    onChange={handleChange}
                    className="input-field"
                />
            </label>
            <br />
            <label>
                Email:
                <input
                    type="email"
                    name="email"
                    value={formData.email}
                    onChange={handleChange}
                    className="input-field"
                />
            </label>
            <br />
            <label>
                Message:
                <textarea
                    name="message"
                    value={formData.message}
                    onChange={handleChange}
                    className="input-field"
                />
            </label>
            <br />
            <button type="submit"
                className="submit-button">
                Submit
            </button>
        </form>
    );
}
 
export default App;


Javascript




// useSyncExternalStore.js
 
import {
    useState,
    useEffect
} from 'react';
 
function useSyncExternalStore(key, initialValue) {
    const [storedValue, setStoredValue] =
        useState(
            () => {
                const item =
                    window.localStorage.getItem(key);
                return item ? JSON.parse(item) : initialValue;
            }
        );
 
    useEffect(
        () => {
            window.localStorage
                .setItem(key, JSON.stringify(storedValue));
        }, [key, storedValue]);
 
    return [storedValue, setStoredValue];
}
 
export default useSyncExternalStore;


Output:

Animation2

Conclusion:

The useSyncExternalStore hook in React provides a simple yet powerful solution for synchronizing component state with an external data store. By persisting state across browser sessions and enabling cross-tab communication, this hook enhances user experiences and simplifies state management in React applications. Consider integrating useSyncExternalStore into your projects to unlock seamless state synchronization capabilities.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads