lobehub/docs/development/state-management/state-management-intro.mdx
René Wang 3dfc86fd0f
feat: Update user guide & changelog (#11518)
* feat: Redesign doc

* chore: uopdate site

* chore: uopdate site

* chore: uopdate site

* chore: uopdate site

* chore: uopdate site

* feat: Uopdate content

* chore: New doc

* chore: Update content

* chore: Update content

* chore: add images

* chore: add images

* chore: add images

* chore: add images

* feat: Add more images

* feat: Add more images

* fix: Cannot reach end

* chore: Update content

* chore: Update content

* chore: Update content

* chore: Update content

* chore: Update content

* Revise README content and structure

Updated README to reflect changes in project description and removed outdated notes.

* Revise 'Getting Started' and TOC in README

Updated the 'Getting Started' section and modified the table of contents.

* chore: Update content

* Revise README structure and content

Updated the Getting Started section and removed the Table of Contents. Adjusted the Local Development instructions.

* Remove custom themes section from README

Removed section about custom themes from README.

* Update README.md

* Refine introduction and highlight cloud version

Updated wording for clarity and added recommendation for cloud version.

* chore: Update content

* chore: Update content

* chore: Update content

* chore: Update content

* chore: Update content

* chore: Update content

* chore: Update content

* fix: add missing translation

* 🔀 chore: Move README changes to feat/readme branch

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: add missing translation

* chore: update cdn

* docs: add migration guide from v1.x local database to v2.x and update help sections

Signed-off-by: Innei <tukon479@gmail.com>

* fix: add missing translation

* fix: add missing images

* fix: add missing changelogs

* fix: add missing changelogs

* fix: add missing changelogs

* fix: add missing changelogs

* fix: add missing changelogs

* style: update cdn

---------

Signed-off-by: Innei <tukon479@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: canisminor1990 <i@canisminor.cc>
Co-authored-by: Innei <tukon479@gmail.com>
2026-01-26 15:28:33 +08:00

229 lines
12 KiB
Text

---
title: Best Practices for State Management
description: >-
Explore effective state management practices for LobeHub's complex data flow
architecture.
tags:
- State Management
- LobeHub
- Data Flow
- Best Practices
---
# Best Practices for State Management
LobeHub differs from traditional CRUD web applications in that it involves a large amount of rich interactive capabilities. Therefore, it is crucial to design a data flow architecture that is easy to develop and maintain. This document will introduce the best practices for data flow management in LobeHub.
## Key Concepts
| Concept | Explanation |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| store | The store contains the application's state and actions. It allows access to and modification of the state during application rendering. |
| state | State refers to the data of the application, storing the current state of the application. Any change in the state will **trigger a re-rendering** to reflect the new state. |
| action | An action is an operation function that describes the interactive events occurring in the application. Actions are typically triggered by user interactions, network requests, or timers. Actions can be **synchronous** or **asynchronous**. |
| reducer | A reducer is a pure function that takes the current state and action as parameters and returns a new state. It is used to update the application's state based on the action type. A reducer is a pure function with no side effects, therefore it is always a **synchronous** function. |
| selector | A selector is a function used to retrieve specific data from the application's state. It takes the application's state as a parameter and returns computed or transformed data. Selectors can combine parts of the state or multiple states to generate derived data. Selectors are commonly used to map the application's state to a component's props for the component's use. |
| slice | A slice is a concept used to express a part of the data model state. It specifies a state slice and its related state, action, reducer, and selector. Using slices, a large store can be divided into smaller, maintainable subtypes. |
## Hierarchical Structure
The structure of the Store can vary greatly depending on the complexity:
- **Low Complexity**: Generally includes 2 to 5 states and 3 to 4 actions. In this case, the structure usually consists of a `store.ts` and an `initialState.ts`.
```bash
DataFill/store
├── index.ts
└── initialState.ts
```
- **Moderate Complexity**: Typically involves 5 to 15 states and 5 to 10 actions, with the possibility of selectors for derived states and reducers to simplify data changes. The structure usually includes a `store.ts`, an `initialState.ts`, and a `selectors.ts`/`reducer.ts`.
```bash
IconPicker/store
├── index.ts
├── initialState.ts
├── selectors.ts
└── store.ts
```
```bash
SortableList/store
├── index.ts
├── initialState.ts
├── listDataReducer.ts
└── store.ts
```
- **Medium Complexity**: Involves 15 to 30 states and 10 to 20 actions, often requiring the use of multiple slices to manage different actions. The following code represents the internal data flow of the `SortableTree` component:
```bash
SortableTree/store
├── index.ts
├── initialState.ts
├── selectors.ts
├── slices
│ ├── crudSlice.ts
│ ├── dndSlice.ts
│ └── selectionSlice.ts
├── store.ts
└── treeDataReducer.ts
```
- **High Complexity**: Involves over 30 states and 20 actions, requiring modular cohesion using slices. Each slice declares its own initState, actions, reducers, and selectors.
The directory structure of the previous version of SessionStore for LobeHub, with high complexity, implements a large amount of business logic. However, with the modularization of slices and the fractal architecture, it is easy to find the corresponding modules, making it easy to maintain and iterate on new features.
```bash
LobeHub SessionStore
├── index.ts
├── initialState.ts
├── selectors.ts
├── slices
│ ├── agentConfig
│ │ ├── action.ts
│ │ ├── index.ts
│ │ ├── initialState.ts
│ │ └── selectors.ts
│ ├── chat
│ │ ├── actions
│ │ │ ├── index.ts
│ │ │ ├── message.ts
│ │ │ └── topic.ts
│ │ ├── index.ts
│ │ ├── initialState.ts
│ │ ├── reducers
│ │ │ ├── message.ts
│ │ │ └── topic.ts
│ │ ├── selectors
│ │ │ ├── chat.ts
│ │ │ ├── index.ts
│ │ │ ├── token.ts
│ │ │ ├── topic.ts
│ │ │ └── utils.ts
│ │ └── utils.ts
│ └── session
│ ├── action.ts
│ ├── index.ts
│ ├── initialState.ts
│ ├── reducers
│ │ └── session.ts
│ └── selectors
│ ├── export.ts
│ ├── index.ts
│ └── list.ts
└── store.ts
```
Based on the provided directory structure of LobeHub SessionStore, we can update the previous document and convert the examples to the implementation of LobeHub's SessionStore. The following is a portion of the updated document:
### Best Practices for LobeHub SessionStore Directory Structure
In the LobeHub application, session management is a complex functional module, so we use the Slice pattern to organize the data flow. Below is the directory structure of LobeHub SessionStore, where each directory and file has its specific purpose:
{/* eslint-disable no-irregular-whitespace */}
```bash
src/store/session
├── helpers.ts # Helper functions
├── hooks # Custom React hooks
│   ├── index.ts # Export file for hooks
│   ├── useEffectAfterHydrated.ts # Hook for effects after session hydration
│   ├── useOnFinishHydrationSession.ts # Hook for session hydration completion
│   ├── useSessionChatInit.ts # Hook for session chat initialization
│   └── useSessionHydrated.ts # Hook for session hydration status
├── index.ts # Aggregated export file for SessionStore
├── initialState.ts # Aggregated initialState for all slices
├── selectors.ts # Selectors exported from various slices
├── slices # Separated functional modules
│   ├── agent # State and operations related to agents
│   │   ├── action.ts # Action definitions related to agents
│   │   ├── index.ts # Entry file for agent slice
│   │   ├── selectors.test.ts # Tests for agent-related selectors
│   │   └── selectors.ts # Selector definitions related to agents
│   └── session # State and operations related to sessions
│   ├── action.test.ts # Tests for session-related actions
│   ├── action.ts # Action definitions related to sessions
│   ├── helpers.ts # Helper functions related to sessions
│   ├── initialState.ts # Initial state for session slice
│   └── selectors # Session-related selectors and their tests
│   ├── export.ts # Aggregated export for session selectors
│   ├── index.ts # Entry file for session selectors
│   ├── list.test.ts # Tests for list selectors
│   └── list.ts # Definitions for list-related selectors
└── store.ts # Creation and usage of SessionStore
```
## Implementation of SessionStore
In LobeHub, the SessionStore is designed as the core module for managing session state and logic. It consists of multiple Slices, with each Slice managing a relevant portion of state and logic. Below is a simplified example of the SessionStore implementation:
### store.ts
```ts
import { PersistOptions, devtools, persist, subscribeWithSelector } from 'zustand/middleware';
import { shallow } from 'zustand/shallow';
import { devtools } from 'zustand/middleware';
import { createWithEqualityFn } from 'zustand/traditional';
import { SessionStoreState, initialState } from './initialState';
import { AgentAction, createAgentSlice } from './slices/agent/action';
import { SessionAction, createSessionSlice } from './slices/session/action';
// =============== Aggregate createStoreFn ============ //
export type SessionStore = SessionAction & AgentAction & SessionStoreState;
const createStore: StateCreator<SessionStore, [['zustand/devtools', never]]> = (...parameters) => ({
...initialState,
...createAgentSlice(...parameters),
...createSessionSlice(...parameters),
});
// =============== Implement useStore ============ //
export const useSessionStore = createWithEqualityFn<SessionStore>()(
persist(
subscribeWithSelector(
devtools(createStore, {
name: 'LobeHub_Session' + (isDev ? '_DEV' : ''),
}),
),
persistOptions,
),
shallow,
);
```
In this `store.ts` file, we create a `useSessionStore` hook that uses the `zustand` library to create a global state manager. We merge the initialState with the actions from each Slice to create a complete SessionStore.
### slices/session/action.ts
```ts
import { StateCreator } from 'zustand';
import { SessionStore } from '@/store/session';
export interface SessionActions {
/**
* A custom hook that uses SWR to fetch sessions data.
*/
useFetchSessions: () => SWRResponse<any>;
}
export const createSessionSlice: StateCreator<
SessionStore,
[['zustand/devtools', never]],
[],
SessionAction
> = (set, get) => ({
useFetchSessions: () => {
// ...logic for initializing sessions
},
// ...implementation of other actions
});
```
In the `action.ts` file, we define a `SessionActions` interface to describe session-related actions and implement a `useFetchSessions` function to create these actions. Then, we merge these actions with the initial state to form the session-related Slice.
Through this layered and modular approach, we can ensure that LobeHub's SessionStore is clear, maintainable, and easy to extend and test.