美文网首页
React Hook + Typescript + Mobx

React Hook + Typescript + Mobx

作者: NANAISNANA | 来源:发表于2019-12-13 10:11 被阅读0次

1:使用useState()实现一个todoList

把我们需要用到的数据结构都放在一个types.ts文件里面
//types.ts
export interface todoItemInterface {
    id: number,
    text: String,
    completed: boolean
}
export interface todoListInterface {
    todoList: todoItemInterface[]
}
实现TodoItem
//TodoItem.tsx
import * as React from "react";

import {todoItemInterface} from '../../types/types'

export const TodoItem: React.FC<todoItemInterface> = ({id, text, completed}) => (
    <div style={{textDecoration: completed ? 'line-through' : 'none'}}>{text}</div>
);
实现TodoList
//TodoList.tsx
import * as React from "react";
import {todoListInterface} from '../../types/types'
import {TodoItem} from '../todoItem/TodoItem'

const TodoList: React.FC<todoListInterface> = ({todoList}) => (
        <ul>
            {todoList.map((todoItem) => (
                <li key={todoItem.id}>
                    <TodoItem id={todoItem.id} text={todoItem.text} completed={todoItem.completed}/>
                </li>

            ))}
        </ul>
    );

export default TodoList;

在App.tsx里面展示TodoList

//App.tsx
import * as React from 'react';
import {useState} from "react";
import TodoList from '../todoList/TodoList'
import {todoItemInterface} from '../../types/types'

function App() {
    const [todos] = useState<todoItemInterface[]>([
        {id: 0, text: 'clean house', completed: false},
        {id: 1, text: 'cook dinner', completed: false}
    ]);
    return (
        <div>
            <h6>React hooks example</h6>
            <TodoList todoList={todos} />
        </div>
    );

}
export default App;

这样我们就能在页面上看到我们的todoList了:


Screen Shot 2019-12-09 at 7.10.08 PM.png

以上是用React hooks+Typescript实现todoList的最简单例子。但是我们的todoList现在还没有任何功能,甚至称不上是一个todoList。接下来,我们给我们的todoList加上toggle的功能。当我们点击一个未完成的todo,给这个todo在样式上加一个横线,表示这个已经完成。如果是点击已经完成的,则把横线去掉,表示并没有完成。
为了完成以上功能,我们有2个task要做:
1: 给todoListInterface添加toggle方法
2:实现toggle方法
3:把toggle方法绑定到每一个todo的onClick事件上

接下来就看看代码实现
1: 给todoListInterface添加toggle方法

//types.ts
export interface todoItemInterface {
   id: number,
   text: String,
   completed: boolean
}
export interface todoListInterface {
   todoList: todoItemInterface[],
   toggleTodo: (id: number)=> void
}

2:实现toggle方法

//App.tsx
import * as React from 'react';
import {useState} from "react";
import TodoList from '../todoList/TodoList'
import {todoItemInterface} from '../../types/types'

function App() {
    let [todos, setTodos] = useState<todoItemInterface[]>([
        {id: 0, text: 'clean house', completed: false},
        {id: 1, text: 'cook dinner', completed: false}
    ]);
    let toggleTodo = (id: number): void => {
        let index = todos.findIndex((item) => {
            return item.id === id;
        });
        let newTodos = todos.map((todo, currentIndex) => {
            if (currentIndex === index) {
                return {...todo, completed: !todo.completed}
            } else {
                return todo;
            }

        });
        //You have to call the setTodos() with a new array reference, Or the TodoItem will
        // not render again.
        setTodos(newTodos);
    };
    return (
        <div>
            <h6>React hooks example</h6>
            <TodoList todoList={todos} toggleTodo={toggleTodo}/>
        </div>
    );

}

export default App;

3:把toggle方法绑定到每一个todo的onClick事件上

//TodoList.tsx
import * as React from "react";
import {todoListInterface} from '../../types/types'
import {TodoItem} from '../todoItem/TodoItem'

const TodoList: React.FC<todoListInterface> = ({todoList, toggleTodo}) => (
    <ul>
        {todoList.map((todoItem) => (
            <li key={todoItem.id}
                onClick={() => {toggleTodo(todoItem.id);console.log('hehe')}}
            >
                <TodoItem id={todoItem.id} text={todoItem.text} completed={todoItem.completed}/>
            </li>

        ))}
    </ul>
);

export default TodoList;

以上,就是实现toggle一个todo,给todo添加或者去掉横线的完整代码。

在toggle方法里面有一个很重要的点就是:

let toggleTodo = (id: number): void => {
        //Other codes
        let newTodos = todos.map( //Other codes);
        setTodos(newTodos);
    };

我们必须给setTodos( )方法传入一个新的array reference,这里我们使用了map( )方法,而map会返回一个新的array。如果依然是把todos传入给setTodos( ),即使complete属性改了,我们的todoItem也不会重新render,因为对于hooks来说,todos是一个array,它的reference没有变,那它就不会触发新的render。
比如,如果采用下面错误的写法,是不会触发新的render的:

    let toggleTodo = (id: number): void => {
        let index = todos.findIndex((item) => {
            return item.id === id;
        });
        todos[index].completed = !todos[index].completed;
        console.dir(todos);
        setTodos(todos);
    };
  

2: 安装mobx-react-lite, mobx

npm install mobx mobx-react-lite 

使用mbox和react hooks的大概task,可以分为以下几步:
1:创建store
2:创建react context
3: 使得react的组件成为observer
4:通过useContext来获取store

接下来就来看一下怎么实现以上具体步骤
1:创建store,&& 2:创建react context

//TodoListStore.ts
import {createContext} from 'react'
import {decorate, observable, computed, action} from 'mobx'
import {todoItemInterface} from '../../types/types'

export class Todos {
    todos: Array<todoItemInterface> = [
        {id: 0, text: 'clean house', completed: false},
        {id: 1, text: 'cook dinner', completed: false}
    ];

    toggleTodo = (id: number): void => {
        let index = this.todos.findIndex((item) => {
            return item.id === id;
        });
        this.todos[index].completed = !this.todos[index].completed;
    };
}

decorate(Todos, {
    todos: observable
});
//创建react context
export default createContext(new Todos());

3: 通过useContext( )获取store

//App.tsx
import * as React from 'react';
import {useContext} from "react";
import TodoList from '../todoList/TodoList'
import todosContext from '../../stores/todoListStore/TodoListStore';

const App = () => {
    const todosStore = useContext(todosContext);
    return (
        <div>
            <h6>React hooks example</h6>
            <TodoList todoList={todosStore.todos} toggleTodo={todosStore.toggleTodo}/>
        </div>
    );

};

export default App;

4: TodoList成为observer

//TodoList.tsx
import * as React from "react";
import {todoListInterface} from '../../types/types'
import {TodoItem} from '../todoItem/TodoItem'
import {observer} from 'mobx-react-lite'

const TodoList: React.FC<todoListInterface> = observer(function ({todoList, toggleTodo}) {
    return (
        <ul>
            {todoList.map((todoItem) => (
                <li key={todoItem.id}
                    onClick={() => {
                        toggleTodo(todoItem.id)
                    }}
                >
                    <TodoItem id={todoItem.id} text={todoItem.text} completed={todoItem.completed}/>
                </li>

            ))}
        </ul>
    )
});

export default TodoList;

因为我们的TodoList是真正使用了store的组件,所以它需要成为一个observer,当store里面的数据(这里是todosStore.todos)变化的时候,TodoList会重新render。

相关文章

网友评论

      本文标题:React Hook + Typescript + Mobx

      本文链接:https://www.haomeiwen.com/subject/nvjbgctx.html