Skip to content

Instantly share code, notes, and snippets.

@ghana7989
Created September 26, 2023 09:06
Show Gist options
  • Save ghana7989/654853d252cdca46d8450c7f0c0ce285 to your computer and use it in GitHub Desktop.
Save ghana7989/654853d252cdca46d8450c7f0c0ce285 to your computer and use it in GitHub Desktop.
Welcome file
# Leveraging Zustand for State Management in React: DevTools Integration & Data Persistence
Zustand is a minimalist state management library for React applications, offering a simple API and a variety of features. In this article, we will delve into how to effectively use Zustand in a React project, focusing on integrating with DevTools for easier debugging and persisting store data for a seamless user experience.
1. **Creating Modular Stores with Zustand:**
Zustand allows for the creation of modular stores to manage state efficiently as your application scales. Here’s a practical example of how to create modular slices and combine them:
```jsx
export const createUserSlice = (set) => ({
users: [],
addUser: (user) => set((state) => ({ users: [...state.users, user] })),
});
export const createThemeSlice = (set) => ({
theme: 'light',
toggleTheme: () => set((state) => ({ theme: state.theme === 'light' ? 'dark' : 'light' })),
});
export const useCombinedStore = create((set, get) => ({
...createUserSlice(set),
...createThemeSlice(set),
}));
```
2. **Integrating with DevTools:**
Integration with DevTools is essential for debugging. The `simple-zustand-devtools` package can be used to achieve this:
```jsx
import create from 'zustand';
import { devtools } from 'simple-zustand-devtools';
const useCustomStore = create(
devtools((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}), 'CustomStore')
);
```
3. **Persisting Store Data:**
To persist store data across sessions, Zustand provides a `persist` middleware. Here’s how you can use it:
```jsx
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
const usePersistentStore = create(
persist(
(set) => ({
tasks: [],
addTask: (task) => set((state) => ({ tasks: [...state.tasks, task] })),
}),
{
name: 'task-storage',
storage: sessionStorage,
}
)
);
```
4. **Managing Asynchronous Hydration:**
When using asynchronous storage, managing hydration is crucial to avoid unexpected behaviors. Zustand offers several methods like `rehydrate()`, `hasHydrated()`, etc., to handle this:
```jsx
const useHydrationStore = create(
persist(
(set) => ({
isAuthenticated: false,
authenticate: () => set({ isAuthenticated: true }),
}),
{ name: 'auth-storage', storage: asyncStorage }
)
);
useEffect(() => {
if (!useHydrationStore.persist.hasHydrated()) {
useHydrationStore.persist.rehydrate();
}
}, []);
```
5. **Adapting to Server-Side Rendering (Next.js):**
In SSR frameworks like Next.js, controlling the timing of hydration is essential. A custom hook can be created to manage this:
```jsx
import { useState, useEffect } from 'react';
const useSSRStore = <T>(storeSelector: (state: any) => T) => {
const initialState = storeSelector(useStore.getState());
const [state, setState] = useState<T>(initialState);
useEffect(() => {
const unsubscribe = useStore.subscribe(
(state) => setState(state),
storeSelector
);
return () => unsubscribe();
}, [storeSelector]);
return state;
};
```
### 6. Usage Section - Component Examples:
Let’s create some React components to demonstrate the usage of the Zustand stores we’ve created.
```jsx
// CounterComponent.jsx
import React from 'react';
import { useCombinedStore } from './store';
const CounterComponent = () => {
const { count, increment, decrement } = useCombinedStore((state) => ({
count: state.count,
increment: state.increment,
decrement: state.decrement,
}));
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
};
```jsx
// ThemeToggle.jsx
import React from 'react';
import { useCombinedStore } from './store';
const ThemeToggleComponent = () => {
const { theme, toggleTheme } = useCombinedStore((state) => ({
theme: state.theme,
toggleTheme: state.toggleTheme,
}));
return (
<div>
<p>Current Theme: {theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
};
```
```jsx
// TaskList.jsx
import React, { useState } from 'react';
import { usePersistentStore } from './store';
const TaskListComponent = () => {
const [task, setTask] = useState('');
const { tasks, addTask } = usePersistentStore((state) => ({
tasks: state.tasks,
addTask: state.addTask,
}));
const handleSubmit = () => {
addTask(task);
setTask('');
};
return (
<div>
<input value={task} onChange={(e) => setTask(e.target.value)} />
<button onClick={handleSubmit}>Add Task</button>
<ul>
{tasks.map((t, index) => (
<li key={index}>{t}</li>
))}
</ul>
</div>
);
};
```
These examples illustrate how Zustand can be used to manage state in different components, showcasing its versatility and ease of use in React applications.
## Conclusion
Zustand offers a lightweight yet powerful solution for state management in React applications. By integrating DevTools and implementing data persistence, developers can ensure a robust and developer-friendly environment. The modular nature of Zustand stores and the ability to manage asynchronous hydration further enhance its utility in diverse React projects.
<!--stackedit_data:
eyJoaXN0b3J5IjpbLTE5NDk5NTQyNzFdfQ==
-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment