Duration: Estimated 15 minutes
For: Developers who are tired of Redux
Code: Warehouse
React 16.13 + TypeScript 3.7 + Mobx 5.15 + mobx-React 6.1
Get a better reading experience
Goal:
Implement a Todo List application as follows
Step 1️ : Create a Store Model
// ./src/stores/todo.ts
import { action, observable, computed } from 'mobx';
export interface ITodo {
id: number;
name: string;
desc: string; done? :boolean;
}
let id = 0;
export class TodoStore {
@observable todos: ITodo[] = [];
// Count the number of incomplete completions using the compute attribute
@computed get doneCount() {
return this.todos.filter(todo= > todo.done).length;
}
@computed get undoneCount() {
return this.todos.filter(todo= >! todo.done).length; }// Add a Todo
@action.bound addNewTodo() {
const i = id++;
const todo = {
name: 'new task' + i,
desc: 'new task' + i,
id: i,
done: false};this.todos = [...this.todos, todo];
}
// Delete a Todo
@action.bound removeById(id: number) {
this.todos = this.todos.filter(todo= >todo.id ! == id); }// Switch to done
@action.bound toggleStatusById(id: number) {
this.todos = this.todos.map(todo= > {
if(todo.id === id) { todo.done = ! todo.done; }returntodo; }); }}export const STORE_TODO = 'todoStore';
Copy the code
Step 2️ : Export Store
// ./src/stores/index.ts
import { createContext, useContext } from 'react';
import { STORE_TODO, TodoStore } from './todo';
function createStores() {
return {
[STORE_TODO]: new TodoStore(),
};
}
const stores = createStores();
const StoresContext = createContext(stores);
/ / hooks to use notes to see here - > https://github.com/olivewind/blog/issues/1
const useStores = (a)= > useContext(StoresContext);
function useTodoStore() {
const { todoStore } = useStores();
return todoStore;
}
export {
stores,
useTodoStore
};
Copy the code
Step 3️ : Usemobx-reactBind the Store to the component
// ./src/app.tsx import React from 'react'; import { Provider } from 'mobx-react'; import Routers from './containers/routers'; import { stores, StoresContext } from './stores'; Function App() {return (// Provider <Provider {... Stores}> {/* Service function components */} <StoresContext.Provider value={stores}> < storesContext. Provider> </Provider>) } export default App;Copy the code
Step 4️ : Use state in function components
// ./src/containers/todo-list-fn/index.tsx import React from 'react'; import { observer } from 'mobx-react'; import { useTodoStore } from '.. /.. /stores'; import { Todo } from '.. /.. /components'; function TodoListFnPage() { const { todos, undoneCount, doneCount, addNewTodo, removeById, toggleStatusById } = useTodoStore(); return ( <div> <div> Done: {doneCount} Undone: {undoneCount} </div> <br /> { todos.map((todo) => { return ( <Todo key={todo.id} todo={todo} onRemove={removeById} switchStatus={toggleStatusById} /> ) }) } <br /> <button onClick={addNewTodo}>Add New</button> </div> ); } export default Observer (TodoListFnPage);Copy the code
Step 5️ : Use state in class components
// ./src/containers/todo-list-class/index.tsx import React from 'react'; import { inject, observer } from 'mobx-react'; import { STORE_TODO, TodoStore } from '.. /.. /stores'; import { Todo } from '.. /.. /components'; @inject(STORE_TODO) @observer class TodoListClassPage extends React.Component<{[STORE_TODO]: TodoStore }> { addNewTodo = () => { this.props[STORE_TODO].addNewTodo(); } render() { const { todos, undoneCount, doneCount } = this.props[STORE_TODO]; return ( <div> <div> Done: {doneCount} Undone: {undoneCount} </div> <br /> { todos.map((todo) => { return ( <Todo key={todo.id} todo={todo} onRemove={this.props[STORE_TODO].removeById} switchStatus={this.props[STORE_TODO].toggleStatusById} /> ) }) } <br /> <button onClick={this.addNewTodo}>Add New</button> </div> ); } } export default TodoListClassPage;Copy the code