// Simple version of Zustand
zustand.js
import React from "react";
// Function to create store with core features
function createStore(createState) {
// Store the current state
let state;
// List of listener functions to update when state changes
const listeners = new Set();
// Function to register listeners
const subscribe = (listener) => {
listeners.add(listener);
// Return the unsubscribe function
return () => listeners.delete(listener);
};
// Function to update the state
const setState = (partial) => {
// Calculate the new state
const nextState = typeof partial === "function" ? partial(state) : partial;
// Check if the state actually changes
if (nextState !== state) {
state = { ...state, ...nextState };
// Notify all listeners
listeners.forEach((listener) => listener(state));
}
};
// Function to get the current state
const getState = () => state;
// Initialize the initial state
state = createState(setState, getState);
// Return methods to work with the store
return {
getState,
setState,
subscribe,
};
}
// Function to create a hook for use in React
function createHook(store) {
return function useStore(selector) {
// React hook to manage state
const [state, setState] = React.useState(
selector ? selector(store.getState()) : store.getState()
);
// Effect to register and unsubscribe listener
React.useEffect(() => {
const handleChange = (newState) => {
const selectedState = selector ? selector(newState) : newState;
// Only update if state changes
setState(selectedState);
};
// Register listener
const unsubscribe = store.subscribe(handleChange);
// Unsubscribe when component unmounts
return unsubscribe;
}, [selector]);
return state;
};
}
// Main function to create store easily
function create(createState) {
// Create store
const store = createStore(createState);
// Create hook to use the store
const useStore = createHook(store);
// Return hook and some additional methods
return Object.assign(useStore, {
getState: store.getState,
setState: store.setState,
subscribe: store.subscribe,
});
}
export { create, createHook, createStore };
// Explanation of how it works:
// 1. createStore: Creates a basic state management mechanism
// - Stores state
// - Allows registering listeners
// - Provides method to update state
// 2. createHook: Creates a React hook to use the store
// - Manages local state
// - Registers listener to track changes
// - Only re-renders when state changes
// 3. create: Main function to create store easily
// - Combines createStore and createHook
// - Provides a simple API to create and use store
// Key principles:
// - Immutability: Always create a new state instead of mutating
// - Minimal API: Only provide necessary methods
// - Performance: Only render when state actually changes
// Main idea of the library:
// Zustand solves state management issues in React by:
// - Creating a central store to store state
// - Providing a mechanism to register and track changes
// - Allowing easy and efficient state updates
// - Minimizing prop-drilling through multiple levels of components
App.js
import React from "react";
import { create } from "./zustand";
// Using the create function defined in the previous code
// Create a store to manage user state
const useUserStore = create((set) => ({
// Initial state
user: null,
isLoggedIn: false,
theme: "light",
// Actions to modify the state
login: (userData) =>
set({
user: userData,
isLoggedIn: true,
}),
logout: () =>
set({
user: null,
isLoggedIn: false,
}),
toggleTheme: () =>
set((state) => ({
theme: state.theme === "light" ? "dark" : "light",
})),
}));
// Profile component using the store
const Profile = () => {
// Access state and actions from the store
const { user, isLoggedIn, login, logout } = useUserStore();
return (
<div className={`p-6 ${isLoggedIn ? "bg-green-100" : "bg-red-100"}`}>
{isLoggedIn ? (
<div>
<h2 className="text-2xl">Hello, {user.name}</h2>
<p>Email: {user.email}</p>
<button
onClick={() => logout()}
className="mt-4 bg-red-500 text-white p-2 rounded"
>
Logout
</button>
</div>
) : (
<button
onClick={() =>
login({
name: "Nguyễn Văn A",
email: "[email protected]",
})
}
className="bg-blue-500 text-white p-2 rounded"
>
Login
</button>
)}
</div>
);
};
// Main component
const UserManagementApp = () => {
return (
<div className="max-w-md mx-auto mt-10 space-y-4">
<h1 className="text-3xl font-bold text-center">User Management</h1>
<Profile />
<StateLogger /> {/* Component to display the entire state */}
</div>
);
};
// Component to log the entire state (for demonstration)
const StateLogger = () => {
// Get the entire state
const state = useUserStore();
return (
<div className="bg-gray-100 p-4 rounded">
<h3 className="font-bold mb-2">Current State:</h3>
<pre>{JSON.stringify(state, null, 2)}</pre>
</div>
);
};
export default UserManagementApp;
// Detailed explanation of the example:
// 1. Create a store with multiple states and actions
// 2. Use a selector to get a part of the state
// 3. Different components can access and modify the state
// 4. No need to pass props or use Context
// 5. Easy to extend and manage global state
https://codesandbox.io/p/sandbox/zustand-simple-6pdqrx?file=%2Fsrc%2FApp.js