MobX-React-Lite 使用指南

56 阅读2分钟

在React项目中集成MobX,你可以按照以下步骤进行操作。MobX是一个流行的状态管理库,它可以帮助你以简洁的方式管理复杂的应用状态。

基础概念

MobX-React-Lite 是 MobX 的轻量级 React 绑定版本,专门用于函数组件。主要概念包括:

  • Observable State: 可观察状态
  • Actions: 修改状态的动作
  • Computed Values: 计算值
  • Reactions: 响应变化
npm install mobx mobx-react-lite

Store 定义

基本 Store

// stores/counter.ts
import { makeAutoObservable } from 'mobx';

export class CounterStore {
	count = 0;

	constructor() {
		makeAutoObservable(this);
	}

	increment() {
		this.count++;
	}

	decrement() {
		this.count--;
	}

	// 计算属性
	get doubleCount() {
		return this.count * 2;
	}
}

export const counterStore = new CounterStore();

Root Store

// stores/index.ts
import { createContext, useContext } from 'react';

import { CounterStore } from './counter';
import { TodoStore } from './todo';

export class RootStore {
	counterStore: CounterStore;
	todoStore: TodoStore;

	constructor() {
		this.counterStore = new CounterStore();
		this.todoStore = new TodoStore();
	}
}

const StoreContext = createContext<RootStore>({} as RootStore);

export const StoreProvider = StoreContext.Provider;
export const useStore = () => useContext(StoreContext);

在组件中使用

Observer 组件

// components/Counter.tsx
import { observer } from 'mobx-react-lite';
import { useStore } from '../stores';

const Counter = observer(() => {
	const { counterStore } = useStore();

	return (
		<div>
			<h1>Count: {counterStore.count}</h1>
			<h2>Double Count: {counterStore.doubleCount}</h2>
			<button onClick={() => counterStore.increment()}>+</button>
			<button onClick={() => counterStore.decrement()}>-</button>
		</div>
	);
});

export default Counter;

Provider 设置

// App.tsx
import { StoreProvider, RootStore } from './stores';
import Counter from './components/Counter';

const rootStore = new RootStore();

function App() {
	return (
		<StoreProvider value={rootStore}>
			<Counter />
		</StoreProvider>
	);
}

高级用法

异步 Actions

// stores/todo.ts
import { makeAutoObservable, runInAction } from 'mobx';

interface Todo {
	id: number;
	title: string;
	completed: boolean;
}

class TodoStore {
	todos: Todo[] = [];
	loading = false;

	constructor() {
		makeAutoObservable(this);
	}

	async fetchTodos() {
		this.loading = true;
		try {
			const response = await fetch('https:///todos');
			const data = await response.json();
			runInAction(() => {
				this.todos = data;
				this.loading = false;
			});
		} catch (error) {
			runInAction(() => {
				this.loading = false;
			});
		}
	}

	// 计算属性
	get completedTodos() {
		return this.todos.filter((todo) => todo.completed);
	}
}

应用

// components/TodoList.tsx
import { observer } from 'mobx-react-lite';
import { useEffect } from 'react';
import { useStore } from '../stores';

const TodoList = observer(() => {
	const { todoStore } = useStore();

	useEffect(() => {
		todoStore.fetchTodos();
	}, []);

	if (todoStore.loading) {
		return <div>Loading...</div>;
	}

	return (
		<div>
			<h1>Todos ({todoStore.completedTodos.length} completed)</h1>
			{todoStore.todos.map((todo) => (
				<div key={todo.id}>
					<input type="checkbox" checked={todo.completed} onChange={() => (todo.completed = !todo.completed)} />
					{todo.title}
				</div>
			))}
		</div>
	);
});

使用 computed

class TodoStore {
	todos = [];
	filter = 'all'; // 'all' | 'active' | 'completed'

	get filteredTodos() {
		switch (this.filter) {
			case 'active':
				return this.todos.filter((todo) => !todo.completed);
			case 'completed':
				return this.todos.filter((todo) => todo.completed);
			default:
				return this.todos;
		}
	}
}

实践

Store 组织

// stores/types.ts
export interface Todo {
	id: number;
	title: string;
	completed: boolean;
}

// stores/todo.ts
import { Todo } from './types';

class TodoStore {
	todos: Todo[] = [];
	// ... 其他实现
}

// stores/index.ts
export { Todo } from './types';
export { todoStore } from './todo';

TypeScript 支持

// stores/index.ts
import { createContext, useContext } from 'react';

interface StoreType {
	counterStore: CounterStore;
	todoStore: TodoStore;
}

const StoreContext = createContext<StoreType | null>(null);

export const useStore = () => {
	const store = useContext(StoreContext);
	if (!store) {
		throw new Error('useStore must be used within a StoreProvider');
	}
	return store;
};

注意事项

  • 只在需要的组件上使用 observer
  • 避免在渲染中创建新的对象或数组
  • 使用 computed 缓存复杂计算
  • 异步操作使用 runInAction
  • 保持 store 结构扁平

mobx持久化

import { makeAutoObservable } from 'mobx'
import { makePersistable } from 'mobx-persist-store' // 引入makePersistable方法进行持久化存储

export default class useMobxStore {
  count: number = 0
  constructor() {
    // 响应式处理
    makeAutoObservable(this)
    // makePersistable 数据持久化存储
    makePersistable(this, {
      name: 'mobxDemo', // 存储到localStorage当中的key值是什么,此处为字符串string;
      properties: ['count'], // 需要持久化的数据是什么,此数据需要为上面声明了的变量,并且传值方式为[string]
      storage: window.localStorage, // 你的数据需要用那种方式存储,常见的就是localStorage
    })
  }

  addCount = () => {
    this.count++
    console.log(this.count)
  }
}