原文链接: mobx-react 类似vuex的react版 响应式状态管理
上一篇: 统计自己文章数目 cheerio
下一篇: mobx-react 多个store 和 全局状态
风格上和react的不可变数据有些不太一样, 但是使用上确实和vuex很像
安装
https://github.com/mobxjs/mobx-react
yarn add mobx mobx-react
简单计数器
import React from 'react';
import { useLocalStore, useObserver } from 'mobx-react';
export default () => {
const todo = useLocalStore(() => ({
count: 0,
inc() {
this.count++;
},
}));
return useObserver(() => <h1 onClick={todo.inc}>{todo.count}</h1>);
};
计算属性, 初始值和prop的
import React, { useState } from 'react';
import {
observer,
useAsObservableSource,
useLocalStore,
} from 'mobx-react-lite';
interface CounterProps {
multiplier: number;
}
const Counter = observer(function Counter(props: CounterProps) {
const observableProps = useAsObservableSource(props);
const store = useLocalStore(() => ({
count: 1,
get multiplied() {
return observableProps.multiplier * this.count;
},
inc() {
this.count += 1;
},
}));
return (
<div>
count :{store.count} Multiplied count: <span>{store.multiplied}</span>
<button id="inc" onClick={store.inc}>
Increment
</button>
</div>
);
});
export default () => {
const [multiplier, setMultiplier] = useState(1);
return (
<div>
multiplier:{multiplier}
<button onClick={() => setMultiplier(v => v + 1)}>add multiplier</button>
<Counter multiplier={multiplier}></Counter>
<Counter multiplier={multiplier + 1}></Counter>
</div>
);
};
一个简单的todo
import React, { FC } from 'react';
import { observer, useLocalStore } from 'mobx-react'; // 6.x or mobx-react-lite@1.4.0
const createTodos = (init: string[]) => {
return init.reduce((pre, cur) => {
pre[cur] = true;
return pre;
}, {} as Record<string, boolean>);
};
const Todo: FC<{
done: boolean;
text: string;
onToggle: (todo: string) => void;
}> = ({ done, text, onToggle }) => {
return (
<div>
done:{done.toString()},text:{text}
<button onClick={() => onToggle(text)}>change</button>
</div>
);
};
const TodoList: FC<{ initialTodos: string[] }> = observer(
({ initialTodos }) => {
const todoRef = React.useRef();
const store = useLocalStore(() => ({
todos: createTodos(initialTodos) as Record<string, boolean>,
get pendingTodos() {
return Object.keys(store.todos).filter(
todo => store.todos[todo] === false
);
},
get doneTodos() {
return Object.keys(store.todos).filter(
todo => store.todos[todo] === true
);
},
addTodo: () => {
store.todos[todoRef.current.value] = false;
todoRef.current.value = '';
},
toggleTodo: (todo: string) => {
store.todos[todo] = !store.todos[todo];
},
}));
const renderTodo = (done: boolean) => todo => (
<Todo key={todo} done={done} text={todo} onToggle={store.toggleTodo} />
);
return (
<div>
<h3>pendingTodos</h3>
{store.pendingTodos.map(renderTodo(false))}
<h3>doneTodos</h3>
{store.doneTodos.map(renderTodo(true))}
<br />
<input ref={todoRef} />
<button onClick={store.addTodo}>Add todo</button>
</div>
);
}
);
export default () => {
return <TodoList initialTodos={['hello', 'world']} />;
};