74react_todolist2

发布时间:2020-07-09 14:25:27 作者:chaijowin
来源:网络 阅读:313

 

 

目录

todolist项目:... 1

阶段5,状态的控制和改变:... 1

阶段6gettersetter... 5

阶段7,过滤数据方法调整:... 9

阶段8@computed的使用:... 13

阶段9,完成状态,Symbol类型:... 14

阶段10axios,整合前后端:... 17

 

 

 

todolist项目:

 

阶段5,状态的控制和改变:

ReduxMobx,社区提供的状态管理库;

Redux,代码优秀,使用严格的函数式编程思想,学习曲线陡峭,小项目使用的优势不明显;

 

Mobx,优秀稳定的库,简单方便(内部实现复杂),适合中小项目使用,使用面向对象的方式,易学习和接受,现使用非常广泛;

https://mobx.js.org/

http://cn.mobx.js.org/

mobx实现了观察者模式(订阅+广播模式),观察者观察某个目标,obserable目标对象发生了变化,会通知自己内部注册了的observer观察者;

 

 

./src/index.js

import React from 'react';

import ReactDom from 'react-dom';

 

import TodoApp from './component/TodoApp';

 

import TodoService from './service/service';

 

const service = new TodoService();   //service实例通过props属性传递到组件中

ReactDom.render(<TodoApp service={service}/>, document.getElementById('root'));

 

./src/service/service.js

解决复选框改变,列表不刷新问题:

1、手动修改todos,如下例,相当于change过;

2、用一常量,如@observable changed=false(或changed=时间戳+随机数),但这个变量要在render()中用到,哪怕写{this.props.service.changed}都行反正要用到,否则不会刷新;

import store from 'store';

import {observable} from 'mobx';

 

export default class TodoService {

    constructor() {

        // super();

        this.load();

    }

 

    load() {

        store.each((value,key) => {

            if (key.startsWith(TodoService.NAMESPACE))

                // this.todos.push(value);

                this.todos.set(key, value);

        });

        console.log(this.todos);

    }

   

    static NAMESPACE = 'todo::';

 

    // todos = [];

    @observable   //观察目标

    todos = new Map();

 

    create(title) {

        // console.log('service');

        const todo = {

            key: TodoService.NAMESPACE + (new Date()).valueOf(),

            title: title,

            completed: false

        };

 

        // this.todos.push(todo);

        this.todos.set(todo.key, todo);

        store.set(todo.key, todo);

        return todo;

    }

 

    setTodoState(key, checked) {

        let todo = this.todos.get(key);

        if (todo) {

            todo.completed = checked;

            store.set(key, todo);

        }

        let temp = this.todos;   //改变观察目标,解决Checkbox复选框改变列表不刷新问题

        this.todos = {};   //this.todos = () => {}

        this.todos = temp;

    }

}

 

./src/component/TodoApp.js

this.props.service.create(event.target.value)index.js已定义,此处用props属性访问;

之前的this.state=({todos: this.service.todos})注释,当前使用mobx控制状态;

import React from 'react';

import Create from './Create';

// import TodoService from '../service/service';

import Todo from './Todo';

import Filter from './Filter';

import {observer} from 'mobx-react';   //注意此处是mobx-react

 

@observer

export default class TodoApp extends React.Component {

    constructor(props) {

        super(props);

        // this.service = new TodoService();

        // this.state = ({todos: this.service.todos, filter: 'uncompleted'});

        this.state = ({filter: 'uncompleted'});

    }

 

    // handleCreate(...args) {

    //     console.log('Root handlerCreate');

    //     console.log(this);

    //     console.log('args is ', args);

    // }

    handleCreate(event) {

        // console.log('Root handleCreate');

        // console.log(this);

        // console.log('event is ', event, event.target, event.target.value);

        this.props.service.create(event.target.value);

        // this.setState({todos: this.service.todos});

    }

 

    handleCheckedChange(key, checked) {   //handleCheckedChange(event),event.target.checked=false|true

        console.log('handleCheckedChange', key, checked);

        this.props.service.setTodoState(key, checked);

        // this.setState({todos: this.service.todos});

    }

 

    handleFilterChange(value) {

        // console.log('~~~~~~~', args);

        // console.log(this);

        console.log(value);

        this.setState({filter: value});;

    }

 

    render() {

        return (

            <div>

                <Create onCreate={this.handleCreate.bind(this)}/>

                <Filter onChange={this.handleFilterChange.bind(this)}/>

                <br />

                {/* {this.service.todos.map(

                    item => <Todo todo={item} key={item.key} onChange={this.handleCheckedChange.bind(this)}/>)

                } */}

                {/* {

                    [...this.service.todos.values()].map(

                        item => <Todo key={item.key} todo={item} onChange={this.handleCheckedChange.bind(this)} />

                    )

                } */}

                {

                    [...this.props.service.todos.values()].filter(

                        item => {

                            let fs = this.state.filter;

                            if(fs === 'all') {

                                return true;

                            } else if(fs === 'completed') {

                                // if(item.completed === true)

                                //     return true;

                                // else

                                //     return false;

                                return item.completed === true;

                            } else if(fs === 'uncompleted') {

                                // if(item.completed === false)

                                //     return true;

                                // else

                                //     return false;

                                return item.completed === false;

                            }

                        }

                    ).map(

                        item => <Todo key={item.key} todo={item} onChange={this.handleCheckedChange.bind(this)} />

                    )

                }

            </div>

        );

    }

}

 

./src/component/{Create.js,Todo.js,Filter.js}不动;

 

 

 

阶段6gettersetter

类似pyproperty装饰器;

 

./src/service/service.js

import store from 'store';

import {observable} from 'mobx';

 

export default class TodoService {

    constructor() {

        // super();

        this.load();

    }

 

    load() {

        store.each((value,key) => {

            if (key.startsWith(TodoService.NAMESPACE))

                // this.todos.push(value);

                this._todos.set(key, value);

        });

        // console.log(this.todos);

    }

   

    static NAMESPACE = 'todo::';

 

    // todos = [];

    @observable

    _todos = new Map();

 

    get todos() {   //getter

        return this._todos;

    }

   

    create(title) {

        // console.log('service');

        const todo = {

            key: TodoService.NAMESPACE + (new Date()).valueOf(),

            title: title,

            completed: false

        };

 

        // this.todos.push(todo);

        this._todos.set(todo.key, todo);

        store.set(todo.key, todo);

 

        let temp = this._todos;   //类似setter;这三句放到此处,解决新创建的待办事宜的刷新问题

        this._todos = {};

        this._todos = temp;

 

        return todo;

    }

 

    setTodoState(key, checked) {

        let todo = this._todos.get(key);

        if (todo) {

            todo.completed = checked;

            store.set(key, todo);

        }

 

        let temp = this._todos;   //setter

        this._todos = {};   //this.todos = () => {}

        this._todos = temp;

    }

}

 

./src/component/TodoApp.js

import React from 'react';

import Create from './Create';

// import TodoService from '../service/service';

import Todo from './Todo';

import Filter from './Filter';

import {observer} from 'mobx-react';

 

@observer

export default class TodoApp extends React.Component {

    constructor(props) {

        super(props);

        // this.service = new TodoService();

        // this.state = ({todos: this.service.todos, filter: 'uncompleted'});

        this.state = ({filter: 'uncompleted'});

    }

 

    // handleCreate(...args) {

    //     console.log('Root handlerCreate');

    //     console.log(this);

    //     console.log('args is ', args);

    // }

    handleCreate(event) {

        // console.log('Root handleCreate');

        // console.log(this);

        // console.log('event is ', event, event.target, event.target.value);

        this.props.service.create(event.target.value);

        // this.setState({todos: this.service.todos});

    }

 

    handleCheckedChange(key, checked) {   //handleCheckedChange(event),event.target.checked=false|true

        // console.log('handleCheckedChange', key, checked);

        this.props.service.setTodoState(key, checked);

        // this.setState({todos: this.service.todos});

    }

 

    handleFilterChange(value) {

        // console.log('~~~~~~~', args);

        // console.log(this);

        // console.log(value);

        this.setState({filter: value});;

    }

 

    render() {

        return (

            <div>

                <Create onCreate={this.handleCreate.bind(this)}/>

                <Filter onChange={this.handleFilterChange.bind(this)}/>

                <br />

                {/* {this.service.todos.map(

                    item => <Todo todo={item} key={item.key} onChange={this.handleCheckedChange.bind(this)}/>)

                } */}

                {/* {

                    [...this.service.todos.values()].map(

                        item => <Todo key={item.key} todo={item} onChange={this.handleCheckedChange.bind(this)} />

                    )

                } */}

                {

                    [...this.props.service.todos.values()].filter(

                        item => {

                            let fs = this.state.filter;

                            if(fs === 'all') {

                                return true;

                            } else if(fs === 'completed') {

                                // if(item.completed === true)

                                //     return true;

                                // else

                                //     return false;

                                return item.completed === true;

                            } else if(fs === 'uncompleted') {

                                // if(item.completed === false)

                                //     return true;

                                // else

                                //     return false;

                                return item.completed === false;

                            }

                        }

                    )

                    .map(

                        item => <Todo key={item.key} todo={item} onChange={this.handleCheckedChange.bind(this)} />

                    )

                }

            </div>

        );

    }

}

 

 

 

阶段7,过滤数据方法调整:

将过滤数据的filter,移到service.js中;

 

./src/service/service.js

import store from 'store';

import {observable} from 'mobx';

 

export default class TodoService {

    constructor() {

        // super();

        this.load();

    }

 

    load() {

        store.each((value,key) => {

            if (key.startsWith(TodoService.NAMESPACE))

                // this.todos.push(value);

                this._todos.set(key, value);

        });

        // console.log(this.todos);

    }

   

    static NAMESPACE = 'todo::';

 

    // todos = [];

    @observable

    _todos = new Map();

    @observable   //添加观察目标对象

    filter = 'uncompleted';

 

    get todos() {   //getter_todos变量

        // return this._todos;

        return [...this._todos.values()].filter(

            item => {

                let fs = this.filter;

                if(fs === 'all') {

                    return true;

                } else if(fs === 'completed') {

                    // if(item.completed === true)

                    //     return true;

                    // else

                    //     return false;

                    return item.completed === true;

                } else if(fs === 'uncompleted') {

                    // if(item.completed === false)

                    //     return true;

                    // else

                    //     return false;

                    return item.completed === false;

                }

            }

        );

    }

   

    create(title) {

        // console.log('service');

        const todo = {

            key: TodoService.NAMESPACE + (new Date()).valueOf(),

            title: title,

            completed: false

        };

 

        // this.todos.push(todo);

        this._todos.set(todo.key, todo);

        store.set(todo.key, todo);

 

        let temp = this._todos;

        this._todos = {};

        this._todos = temp;

 

        return todo;

    }

 

    setTodoState(key, checked) {

        let todo = this._todos.get(key);

        if (todo) {

            todo.completed = checked;

            store.set(key, todo);

        }

 

        let temp = this._todos;

        this._todos = {};   //this.todos = () => {}

        this._todos = temp;

    }

 

    setTodoFilter(value) {

        this.filter = value;

    }

}

 

./src/component/TodoApp.js

import React from 'react';

import Create from './Create';

// import TodoService from '../service/service';

import Todo from './Todo';

import Filter from './Filter';

import {observer} from 'mobx-react';

 

@observer

export default class TodoApp extends React.Component {

    constructor(props) {

        super(props);

        // this.service = new TodoService();

        // this.state = ({todos: this.service.todos, filter: 'uncompleted'});

        // this.state = ({filter: 'uncompleted'});   //filter使用mobx管理

    }

 

    // handleCreate(...args) {

    //     console.log('Root handlerCreate');

    //     console.log(this);

    //     console.log('args is ', args);

    // }

    handleCreate(event) {

        // console.log('Root handleCreate');

        // console.log(this);

        // console.log('event is ', event, event.target, event.target.value);

        this.props.service.create(event.target.value);

        // this.setState({todos: this.service.todos});

    }

 

    handleCheckedChange(key, checked) {   //handleCheckedChange(event),event.target.checked=false|true

        // console.log('handleCheckedChange', key, checked);

        this.props.service.setTodoState(key, checked);

        // this.setState({todos: this.service.todos});

    }

 

    handleFilterChange(value) {

        // console.log('~~~~~~~', args);

        // console.log(this);

        // console.log(value);

        // this.setState({filter: value});;

        this.props.service.setTodoFilter(value);

    }

 

    render() {

        return (

            <div>

                <Create onCreate={this.handleCreate.bind(this)}/>

                <Filter onChange={this.handleFilterChange.bind(this)}/>

                <br />

                {/* {this.service.todos.map(

                    item => <Todo todo={item} key={item.key} onChange={this.handleCheckedChange.bind(this)}/>)

                } */}

                {/* {

                    [...this.service.todos.values()].map(

                        item => <Todo key={item.key} todo={item} onChange={this.handleCheckedChange.bind(this)} />

                    )

                } */}

                {

                    this.props.service.todos.map(

                        item => <Todo key={item.key} todo={item} onChange={this.handleCheckedChange.bind(this)} />

                    )

                }

            </div>

        );

    }

}

 

 

 

阶段8@computed的使用:

mobx提供了@computed装饰器,可用在任意类的属性的getter上,它所依赖的值发生了变化就重新计算,否则直接返回上次计算的结果;

使用@computed装饰get todos()

 

./src/service/service.js

import {observable, computed} from 'mobx';

export default class TodoService {

……

    @computed   //程序员感知不到变化,观察对象_todosfilter任意一个变化都会重新计算

    get todos() {

        // return this._todos;

        return [...this._todos.values()].filter(

            item => {

                let fs = this.filter;

                if(fs === 'all') {

                    return true;

                } else if(fs === 'completed') {

                    // if(item.completed === true)

                    //     return true;

                    // else

                    //     return false;

                    return item.completed === true;

                } else if(fs === 'uncompleted') {

                    // if(item.completed === false)

                    //     return true;

                    // else

                    //     return false;

                    return item.completed === false;

                }

            }

        );

    }

……

}

 

 

 

阶段9,完成状态,Symbol类型:

Symbol类型,是JS中的基本类型;

ES6新增的主数据类型,是一种特殊的、不可变的数据类型;

Symbol([description])description是可选的字符串;

不可使用new关键字,生成的不是对象,直接用函数调用方式使用;

Symbol每次返回一个独一无二的值,即便2次的描述一样,描述只是为了使人阅读方便,便于区分不同的Symbol值;

 

例:

let sym0 = Symbol();

let sym1 = Symbol();

let sym2 = Symbol('symbol2');

let sym3 = Symbol('symbol2');

 

console.log(sym0 === sym1);

console.log(sym1 === sym2);

输出:

false

false

 

 

./src/service/service.js

import store from 'store';

import {observable, computed} from 'mobx';

 

const ALL = Symbol('all');

const COMPLETED = Symbol('completed');

const UNCOMPLETED = Symbol('uncompleted');

 

export default class TodoService {

    constructor() {

        // super();

        this.load();

    }

 

    load() {

        store.each((value,key) => {

            if (key.startsWith(TodoService.NAMESPACE))

                // this.todos.push(value);

                this._todos.set(key, value);

        });

        // console.log(this.todos);

    }

   

    static NAMESPACE = 'todo::';

    static TODOSTATES = {

        // all: 'all',

        all: ALL,

        // completed: 'completed',

        completed: COMPLETED,

        // uncompleted: 'uncompleted'

        uncompleted: UNCOMPLETED

    }

 

    // todos = [];

    @observable

    _todos = new Map();

    @observable

    // filter = 'uncompleted';

    filter = TodoService.TODOSTATES.uncompleted;

 

    @computed

    get todos() {

        // return this._todos;

        return [...this._todos.values()].filter(

            item => {

                let fs = this.filter;

                // if(fs === 'all') {

                if(fs === TodoService.TODOSTATES.all) {   //只能用类.属性这种方式,不可以fs === Symbol('all'),这样相当于重新调用Symbol()是个新值;===常用,严格相等;==要做隐式转换,不用

                    return true;

                // } else if(fs === 'completed') {

                } else if(fs === TodoService.TODOSTATES.completed) {

                    // if(item.completed === true)

                    //     return true;

                    // else

                    //     return false;

                    return item.completed === true;

                // } else if(fs === 'uncompleted') {

                } else if(fs === TodoService.TODOSTATES.uncompleted) {

                    // if(item.completed === false)

                    //     return true;

                    // else

                    //     return false;

                    return item.completed === false;

                }

            }

        );

    }

   

    create(title) {

        // console.log('service');

        const todo = {

            key: TodoService.NAMESPACE + (new Date()).valueOf(),

            title: title,

            completed: false

        };

 

        // this.todos.push(todo);

        this._todos.set(todo.key, todo);

        store.set(todo.key, todo);

 

        let temp = this._todos;

        this._todos = {};

        this._todos = temp;

 

        return todo;

    }

 

    setTodoState(key, checked) {

        let todo = this._todos.get(key);

        if (todo) {

            todo.completed = checked;

            store.set(key, todo);

        }

 

        let temp = this._todos;

        this._todos = {};   //this.todos = () => {}

        this._todos = temp;

    }

 

    setTodoFilter(value) {

        // this.filter = value;

        this.filter = TodoService.TODOSTATES[value];

    }

}

注:

./src/component/Filter.js

<Select style={{ width: 120 }} defaultValue="uncompleted" onChange={value => props.onChange(value)}>

antddefaultValue={TodoService.TODOSTATE.uncompleted},不支持传递类.属性这种,只能用字符串;

 

 

 

阶段10axios,整合前后端:

axios是一个异步HTTP库,可用在浏览器或nodejs中;

 

例:

axios.get('/user?ID=12345')

  .then(function (response) {   //返回200 OK的处理,response是返回的数据(区别于服务器的响应),具体看MIME类型,可以是picture、下载内容等

    console.log(response);

  })

  .catch(function (error) {   //异常的处理

    console.log(error);

  });

 

注:

前端要操作DB,通过ajaxjquery(早期用)-->web服务器;

url + method --> restful

post   #add

put   #modify

 

store.set(todo.key, todo)   #当前是存储在浏览器本地的Local Storage,实际是要存储在数据库上,这块需改造

 

例:

webpack.config.dev.js   #开发的win主机上更改

    devServer: {

        compress: true,

        port: 3000,

        publicPath: '/assets/',

        hot: true,

        inline: true,

        historyApiFallback: true,

        stats: {

            chunks: false

        },

        proxy: {

            '/api': {

                target: 'http://192.168.23.134:80',   //nginx主机配置

                changeOrigin: true

            }

        }

    }

$ npm run build   #在项目根下打包

 

]# pwd   #nginx主机上操作

/ane/packages

]# tar xf tengine-1.2.3.tar.gz

]# cd tengine-1.2.3/

]# yum -y install gcc openssl-devel pcre-devel

]# ./configure

]# make && make install

]# cd /usr/local/nginx/

]# vim conf/nginx.conf

    server {

        listen       80;

        server_name  localhost;

 

        #charset koi8-r;

 

        #access_log  logs/host.access.log  main;

        location /api/ {

            proxy_pass http://192.168.7.144:8080;   #win主机上运行的py开发的后台app

        }

 

        location / {

            root   html;

            index  index.html index.htm;

        }

]# tree ./   #将打好包的index.htmlapp-56350ea8.js放到nignx上,app-*.js要放到assets/

./

├── 50x.html

├── assets

   └── app-56350ea8.js

└── index.html

]# sbin/nginx   #sbin/nginx -s reload,动态加载配置

]# netstat -tnulp | grep nginx

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      2280/nginx: master 

 

http://192.168.23.134/

74react_todolist2

 

74react_todolist2

注:

nginx配置中先注释location /api/ {……}这段,在create待办事宜时报404

nginx配置中有location /api/ {……}这段,在create待办事宜时报502,因为后端还没开启py开发的后台app

 

 

win主机的pycharm中运行:

from aiohttp import web, log

import json

import logging

 

async def indexhandle(request: web.Request):

    return web.Response(text='welcome to pyserver', status=200)

 

async def handle(request: web.Request):

    print(request.match_info)

    print(request.query_string)

    return web.Response(text=request.match_info.get('id', '0000'), status=200)

 

async def todopost(request: web.Request):   #协程函数

    print(request.method)

    print(request.match_info)

    print(request.query_string)

    print(request.json())

    js = await request.json()   #协程中用,yield from

    print(js, type(js))

    text = dict(await request.post())

    print(text, type(text))

    js.update(text)

    res = json.dumps(js)

    print(res)

    return web.Response(text=res, status=201)   #201状态码表示Created

 

 

app = web.Application()

app.router.add_get('/', indexhandle)

app.router.add_get('/{id}', handle)

app.router.add_post('/api/todo', todopost)

 

app.logger.setLevel(level=logging.NOTSET)

web.run_app(app, host='0.0.0.0', port=8080)

输出:

======== Running on http://0.0.0.0:8080 ========

(Press CTRL+C to quit)

POST

<MatchInfo {}: <ResourceRoute [POST] <PlainResource  /api/todo> -> <function todopost at 0x0000000003997A60>>

 

<coroutine object BaseRequest.json at 0x0000000003970F68>

{'completed': False, 'key': 'todo::1543038271618', 'title': 'test'} <class 'dict'>

{} <class 'dict'>

{"completed": false, "key": "todo::1543038271618", "title": "test"}

 

http://192.168.23.134

74react_todolist2

 

 


推荐阅读:
  1. O2OA开源免费开发平台:在O2门户页面中使用React(一)
  2. react中如何传递事件对象

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

react todolist js

上一篇:tableView 属性设置

下一篇:在js中call、apply和bind之间有什么区别

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》