MobX-React-Lite 使用方法总结

302 阅读2分钟

1. 基础概念

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

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

2. 安装

npm install mobx mobx-react-lite
# 或
yarn add mobx mobx-react-lite

3. Store 定义

3.1 基本 Store

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

class CounterStore {
	count = 0;

	constructor() {
		makeAutoObservable(this);
	}

	increment() {
		this.count++;
	}

	decrement() {
		this.count--;
	}

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

export const counterStore = new CounterStore();

3.2 Root Store

// stores/index.ts
import { createContext, useContext } from 'react';
import { CounterStore } from './counter';
import { TodoStore } from './todo';

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);

4. 在组件中使用

4.1 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;

4.2 Provider 设置

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

const rootStore = new RootStore();

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

5. 高级用法

5.1 异步 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://api.example.com/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);
	}
}

5.2 Reactions

// 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>
	);
});

6. 性能优化

6.1 细粒度观察

// components/TodoItem.tsx
import { observer } from 'mobx-react-lite';

const TodoItem = observer(({ todo }) => {
	return (
		<div>
			<input type="checkbox" checked={todo.completed} onChange={() => (todo.completed = !todo.completed)} />
			{todo.title}
		</div>
	);
});

// components/TodoList.tsx
const TodoList = observer(() => {
	const { todoStore } = useStore();

	return (
		<div>
			{todoStore.todos.map((todo) => (
				<TodoItem key={todo.id} todo={todo} />
			))}
		</div>
	);
});

6.2 使用 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;
		}
	}
}

7. 最佳实践

7.1 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';

7.2 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;
};

8. 注意事项

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

9. 调试

9.1 开发工具

// index.tsx
import { configure } from 'mobx';

if (process.env.NODE_ENV === 'development') {
	configure({
		enforceActions: 'always',
		computedRequiresReaction: true,
		reactionRequiresObservable: true,
	});
}

9.2 使用 MobX DevTools

npm install mobx-react-devtools
import { observer } from 'mobx-react-lite';
import DevTools from 'mobx-react-devtools';

const App = observer(() => {
	return (
		<>
			<div>Your App Content</div>
			{process.env.NODE_ENV === 'development' && <DevTools />}
		</>
	);
});

10. 总结

MobX-React-Lite 提供了一种简单而强大的状态管理解决方案,特别适合中小型 React 应用。通过合理使用 observable、action、computed 等特性,可以构建出高效、可维护的应用。更多详细信息请参考官方文档:github.com/mobxjs/mobx…