react項目基本實踐

一 localstorage和基本組件介紹

1 localstorage介紹

localstorage 是瀏覽器端持久化方案之一,HTML5標準增長的技術
localstorage 是爲了存儲交互的數據,如json。
數據存儲就是鍵值在不一樣域名下的存儲
不一樣瀏覽器對單個域名下存儲數據的長度支持不一樣,有的最多支持2MB 前端

以下python

react項目基本實踐

其中sessionstorage是會話級別的存儲,及就是臨時存儲。
localstorage 支持的瀏覽器最多而sessionstorage支持的瀏覽器卻較少。
下面的indexedDB和web SQL 是和數據庫存儲有關,react

indexedDB:
一個域一個datatable
key-value 檢索方式
創建在關係型數據庫上,具備索引表,遊標,事務等概念。webpack

2 store.js

store.js是一個兼容全部瀏覽器的localstorage包裝器,不須要藉助cookie或者flash,store.js會根據瀏覽器自動選擇使用localstorage,globalstorage或者 userdata來實現本地存儲功能。ios


安裝 git

npm  i store  --save //此處是在部署包中添加

react項目基本實踐

介紹和相關說明github

https://github.com/marcuswestin/store.js/web

測試代碼以下 數據庫

var store = require('store') //導入模塊
store.set('user','test')  //設置key,value值
console.log(store.get('user'))  //獲取key,value值
store.remove('user') //移除key,及其和對應的value
console.log(store.get('user','aaaaa')) //查詢不存在時使用默認 
store.clearAll()  //清除全部 
store.set('test','test') // 設置 
store.each(function  (value,key)  {    //遍歷key和value,注意,此處是value,key 
    console.log(key,'====',value)
})

結果以下npm

react項目基本實踐

3 antd組件相關介紹

用戶提交數據,須要表單控件,而這種用戶提交的數據顯示就是view層須要完成的功能,對於react來講是一個空間,但這些控件須要用戶看到,爲了美觀,引入了antd。


ant Design 螞蟻金服開源的reactUI庫

antd官網

https://ant.design/index-cn

官方文檔

https://ant.design/docs/react/introduce-cn

1 Input組件

使用一種較爲簡單的組件Input來完成輸入功能

地址以下

https://ant.design/components/input-cn/

基礎代碼以下

import { Input } from 'antd';

ReactDOM.render(<Input placeholder="Basic usage" />);

輸入框屬性

addonAfter 帶標籤的 input,設置後置標籤 string|ReactNode
addonBefore 帶標籤的 input,設置前置標籤 string|ReactNode
placeholder="Basic usage" 佔位詞
size="smail" 小輸入框,改成large就是大輸入框

2 Card 組件

顯示一個較爲友好的界面

地址以下

https://ant.design/components/card-cn/

相關映射以下,最後面的style={{width:300}} 表示樣式,其是指寬度

react項目基本實踐

3 CheckBox多選框

相關處理可使用checkbox組件來完成,選中和取消選中

https://ant.design/components/checkbox-cn/#header

基礎代碼以下

import { Checkbox } from 'antd';

function onChange(e) {
  console.log(`checked = ${e.target.checked}`);  //打印選擇結果 
}
//onChange 選中,取消時觸發回調函數.checked 表示是否選中,若選中,則爲true,未選中,則爲false 
ReactDOM.render(<Checkbox   onChange={onChange}>Checkbox</Checkbox>, mountNode);

4 柵格顯示

https://ant.design/components/grid-cn/

佈局上,ant design 和 bootstrap很像,都使用一套柵格系統,使用24柵格,也就是每個內部都切分紅24份

import React  from  'react';
import  {Checkbox,Card,Row,Col}   from  'antd';
import  'antd/lib/row/style';
import 'antd/lib/card/style';
import 'antd/lib/Col/style';

//一條待辦事宜
export  default  props => (
    <Card  style={{width:600}}>
        <Row>
            <Col span="4"><Checkbox /></Col>
            <Col span="20">{props.todo.title}</Col>
        </Row> 
      </Card> 
);

5 Select 對的篩選和顯示

過濾是指,過濾什麼狀態的待辦事宜
應該有3種選擇:未完成,完成的和所有的,和後面的completed 參數結合使用。

使用select模塊來完成選擇框的使用,相關地址以下

https://ant.design/components/select-cn/
import { Select } from 'antd';

const { Option } = Select;

function onChange(value) {
  console.log(`selected ${value}`);
}

function onBlur() {
  console.log('blur');
}

function onFocus() {
  console.log('focus');
}

function onSearch(val) {
  console.log('search:', val);
}

ReactDOM.render(
  <Select
    showSearch
    style={{ width: 200 }}
    placeholder="Select a person"
    optionFilterProp="children"
    onChange={onChange}
    onFocus={onFocus}
    onBlur={onBlur}
    onSearch={onSearch}
    filterOption={(input, option) =>
      option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
    }
  >
    <Option value="jack">Jack</Option>
    <Option value="lucy">Lucy</Option>
    <Option value="tom">Tom</Option>
  </Select>,

4 Map 用於數據的持久化處理

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map

相關測試代碼以下

m=new Map();
m.set(1,'a');  //定義key和value 
m.set(2,'b');
m.set(3,'c');

console.log(m);  //查看結果 

let t=m.forEach((value,key)=> [key,value]);  // 此處無返回值 

console.log(t);  

t=[...m.values()].map(item => item+100);  // 對可迭代對象的解構,並進行處理,map 當即返回
console.log(t)

結果以下

react項目基本實踐

5 狀態管理Mobx

Redux 和 Mobx

上述項目中基本功能都實現了。但state的控制顯得有些麻煩。

社區提供了狀態管理庫,有Redux和Mobx

Redux 代碼優秀,使用嚴格的函數式編程思想,學習曲線陡峭,小項目使用的優點不明顯
Mobx,穩定,使用簡單方便,適合中小型項目的使用,使用面向對象的方式學習,容易學習和接受,如今,使用也很是普遍。


Mobx 官網

https://mobx.js.org/

中文網

https://cn.mobx.js.org/

Mobx實現了觀察者模式

觀察者模式
觀察者觀察某個目標,目標對象(Obserable)發生了變化,就會通知本身內部註冊的觀察者Observer

react項目基本實踐

觀察者模式,及就是一對多的廣播模式

首先,須要觀察者和被觀察者

目標對象,及被觀察者,obserable 指的是數據的源頭,被觀察者能夠有多個,同時觀察這個變化。只要被觀察的對象有變化,則便會致使觀察者作出相應的操做,state和props變化是咱們關心的,


@computed 的使用

mobx還提供了一個裝飾器@computed,可使用在任意類上屬性的getter上使用,其所依賴的值發生了變化就會從新計算,不然直接返回到上次計算的結果。起到了緩存的做用,可直接用於filter的判斷上,經過傳入的值來進行相關匹配進而進行返回或計算。

6 異步處理和打包部署

異步處理axios
官網

http://www.axios-js.com/zh-cn/docs/

基礎代碼以下

// 爲給定 ID 的 user 建立請求
axios.get('/user?ID=12345')
  .then(function (response) { //返回成功執行的代碼
    console.log(response);
  })
  .catch(function (error) {  //返回失敗執行的代碼  
    console.log(error);
  });

axios.post('/user', {  //下面的兩個表示key和value的值傳遞到服務器端
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

二 業務需求和基本代碼實現

1 需求分析

分層
視圖層,負責顯示數據,每個react 組件一個js文件。

服務層,負責業務數據處理邏輯,命名爲xxxService.js。

model層,負責數據,這裏使用localstore。

注意:未特別說明,這些層的代碼都在項目跟目錄的src中

2 代碼實現

1 服務層實現

此處仍使用上一節項目包,相關介紹以下

http://www.javashuo.com/article/p-egypmnww-h.html


項目包以下
連接:https://pan.baidu.com/s/1C-ZY9rWU-8ZugE4EwVveWw
提取碼:744p

具體項目介紹。請查看上一節 react項目基礎

構建TodoService類,文件名爲service.js,此目前放置在src的目錄下

react項目基本實踐

import  store  from  'store' 
export  default  class TodoService{
    static NAMESPACE="todo"  //定義存儲前綴 
    todos=[];  //定義存儲容器 
    // 建立todo  
    create(title) { //定義函數,用於處理建立和存儲數據
        const todo = {  //定義value類型 
        key: TodoService.NAMESPACE+(new Date()).valueOf(),    /*毫秒時間戳*/
        title :title,  //定義相關類型 
        completed: false //定義數據狀態
        }
        this.todos.push(todo);  //存儲至容器中
        //持久化處理
        store.set(todo.key,todo);
        return todo
    }
}

2 建立數據來源

title 從哪裏來
從瀏覽器端,用戶提交,也就是視圖層提供的用戶提交的文本框,經過Card和 INput來處理數據的接受和啓動問題。


建立create.js 文件,其路徑暫時存放與src目錄下,此安裝包antd默認已經在包中存在,若未安裝,則需使用npm i antd進行安裝


使用這兩個組件組合,基礎測試代碼以下

import  React  from  'react';
import { Card,Input } from 'antd';
import  'antd/lib/card/style'  //導入相關樣式表 
import 'antd/lib/Input/style'
//缺省導出無狀態組件react 中 
export default props  => (
    <Card title="請輸入" style={{ width: 300 }}>
        <Input  />
    <p>測試代碼</p>
     </Card>
)

開放接口層代碼 index.js 相關代碼以下

import React from 'react';   
import ReactDOM from 'react-dom';
import Create  from  './create'  //引入模塊 

class  Root extends  React.Component  {
    render(){
        return  (<div>
            hello world 
            <hr/>
            <Create />   //引入顯示
        </div>)
    }
}
ReactDOM.render(<Root/>,document.getElementById('root'));

結果以下

react項目基本實踐

輸入框處理,爲了能讓用戶提交信息,咱們須要是哦有那個接受回車鍵的事件觸發提交信息,鍵盤按下是一個事件,在Input中使用onPressEnter來收集鍵盤按下回車鍵的觸發指令。

react項目基本實踐

此處代表後面跟的是一個函數

修改以下
打印回車數據,其是經過event.target.value獲取到Input框中的數據的

import  React  from  'react';
import { Card,Input } from 'antd';
import  'antd/lib/card/style'  //導入相關樣式表 
import 'antd/lib/Input/style'
//缺省導出無狀態組件react 中 
export default props  => (
    <Card title="請輸入" style={{ width: 300 }}>
        <Input  onPressEnter={(event)  =>{console.log(event.target.value)}}/>  {/*此處使用event表示觸發的事件,其表示獲取到用戶數據*/}
    <p>測試代碼</p>
     </Card>
)

拿到用戶數據,應該調用todoservice的create,但不適合在create.js中進行調用,經過props 進行組件之間的數據共享。使用props
Root組件中建立一個handleCreate(title),用於處理Input中的數據傳輸到後臺,經過調用後臺的函數方法來完成。

index.js組件內容

import React from 'react';
import ReactDOM from 'react-dom';
import Create  from  './create'
import    TodoService  from  './service'
class  Root extends  React.Component  {
    constructor(props) {
        super(props);
        this.service = new  TodoService();  //初始化類對象
    }
    handleCreate(title){  
        console.log(title.target.value)  //打印create.js中傳輸的數據
        this.service.create(title.target.value)  //調用todoserver的方法完成數據的持久化操做 
    }
    render(){
        return  (<div>
            hello world 
            <hr/>
            <Create  onCreate={this.handleCreate.bind(this)} />  {/*經過此處的傳遞將oncrete屬性傳遞到後端用於相關的處理*/}
        </div>)
    }
}
ReactDOM.render(<Root/>,document.getElementById('root'));

create.js組件內容

import  React  from  'react';
import { Card,Input } from 'antd';
import  'antd/lib/card/style'  //導入相關樣式表 
import 'antd/lib/Input/style'
//缺省導出無狀態組件react 中 
export default props  => (
    <Card title="請輸入" style={{ width: 300 }}>
        <Input  onPressEnter={(event) => props.onCreate(event)}/>  {/*此處經過外部的index.js中的數據傳遞
        將handleCreate 傳遞過來進行相關的處理操做,其被做爲props攜帶進入此處參與相關的處理和調度操做*/}
    <p>測試代碼</p>
     </Card>
)

結果以下

react項目基本實踐

3 建立添加數據顯示問題

添加數據完成後顯示問題,須要建立用於列表顯示結果,須要建立的包以下,其仍然再src目錄下:Todo.js

import  React  from  'react'
import {  Checkbox,Card,Row,Col } from 'antd'
import  'antd/lib/card/style'
import  'antd/lib/row/style'
import  'antd/lib/card/style'
import  'antd/lib/checkbox/style'

export  default  props =>(
    <Card>
        <Row>
            <Col span={4}><Checkbox  /> }/></Col>
            <Col span={20}>{props.todo.title}</Col>
        </Row>
    </Card>
)

index.js代碼以下

import React from 'react';
import ReactDOM from 'react-dom';
import Create  from  './create'
import TodoService  from  './service'
import Todo from './Todo';
class  Root  extends React.Component {
      constructor (props)  {
        super(props);
        this.service=new  TodoService(); 
        this.state={todos:this.service.todos} //變化引發的刷新操做
      }
      handleCreate (event)  {

        this.service.create(event);
        this.setState({todos:this.service.todos});
      }

      render(){
        return(
            <div>
              <Create onCreate={this.handleCreate.bind(this)} />  {/*本身定義一個屬性,處理props事件的*/}
              {/*完成數據的顯示*/}
              {/* {this.service.todos.forEach}  雖然遍歷,但不返回任何結果 */}
              {this.service.todos.map(item=> <Todo  key={item.key} todo={item} />)}  {/*調用todo進行處理相關的函數問題,map後返回新的容器*/}
            </div>
        );
      }
    }
    ReactDOM.render(<Root />,document.getElementById('root'));  //NewRoot(props)  

結果以下

react項目基本實踐

每添加一個元素,其會顯示該元素。但其在網頁刷新後其會不存在,但在localstorage中存儲全部的數據,所以須要處理裝載數據的函數。

4 數據持久化操做

修改代碼以下

import  store  from  'store' 
export  default  class TodoService{
    static NAMESPACE="todo"  //定義存儲前綴 
    todos= new Map();  //定義存儲容器 
    // 建立todo  
    constructor(){
        this.load();
    }
    load(){
        store.each((value,key) => {
            if (key.startsWith(TodoService.NAMESPACE))
                this.todos.set(key,value)
        }
        )} 

    create(title) { //定義函數,用於處理建立和存儲數據
        const todo = {  //定義value類型 
        key: TodoService.NAMESPACE+(new Date()).valueOf(),    /*毫秒時間戳*/
        title :title,  //定義相關類型 
        completed: false //定義數據狀態
        }
        this.todos.set(todo.key,todo);  //存儲至容器中
        //持久化處理
        store.set(todo.key,todo);
        return todo
    }
}

index.js 代碼修改結果以下

import React from 'react';
import ReactDOM from 'react-dom';
import Create  from  './create'
import TodoService  from  './service'
import Todo from './Todo';
import Filter  from  './filter'
import { set } from 'mobx';
class  Root  extends React.Component {
      constructor (props)  {
        super(props);
        this.service=new  TodoService(); 
      }
      handleCreate (event)  {
        this.service.create(event);
        this.setState({todos:this.service.todos});
      }
      render(){
        return(
            <div>
              <Create onCreate={this.handleCreate.bind(this)} />  {/*本身定義一個屬性,處理props事件的*/}
              {/*完成數據的顯示*/}
              {[...this.service.todos.values()].map( item=> <Todo todo={item}/>)}  {/*調用todo進行處理相關的函數問題,map後返回新的容器*/}
            </div>
        );
      }
    }
    ReactDOM.render(<Root />,document.getElementById('root'));  //NewRoot(props)  
    // Test(Root)(props)

最終結果以下

react項目基本實踐

5 後端狀態的修改實現

不管如何刷新,其最終結果都將會徹底顯示

後端 completed 狀態爲false和true的實現,其主要是經過checkbox 實現

Todo.js修改代碼以下

import React  from  'react';
import  {Checkbox,Card,Row,Col}   from  'antd';
import  'antd/lib/row/style';
import 'antd/lib/card/style';
import 'antd/lib/Col/style';

//一條待辦事宜
export  default  props => (
    <Card  style={{width:600}}>
        <Row>
            <Col span="4"><Checkbox onChange={(event)  =>props.onChage(event.target.checked,props.todo.key)}/></Col>
            <Col span="20">{props.todo.title}</Col>
        </Row> 
      </Card> 
);

後端service代碼

import  store  from  'store' 
export  default  class TodoService{
    static NAMESPACE="todo"  //定義存儲前綴 
    todos= new Map();  //定義存儲容器 
    // 建立todo  
    constructor(){
        this.load();
    }
    load(){
        store.each((value,key) => {
            if (key.startsWith(TodoService.NAMESPACE))
                this.todos.set(key,value)
        }
        )} 

    create(title) { //定義函數,用於處理建立和存儲數據
        const todo = {  //定義value類型 
        key: TodoService.NAMESPACE+(new Date()).valueOf(),    /*毫秒時間戳*/
        title :title,  //定義相關類型 
        completed: false //定義數據狀態
        }
        this.todos.set(todo.key,todo);  //存儲至容器中
        //持久化處理
        store.set(todo.key,todo);
        return todo
    }
    todochaService(key,checked){
        let todo=this.todos.get(key)  //獲取對應的值
        todo.completed=checked;  //賦值
        console.log(todo.completed,checked)
        this.todos.set(key,todo) //刷新map
        store.set(key,todo)  //刷新store 
    }
}

index.js端代碼以下

import React from 'react';
import ReactDOM from 'react-dom';
import Create  from  './create'
import TodoService  from  './service'
import Todo from './Todo';
class  Root  extends React.Component {
      constructor (props)  {
        super(props);
        this.service=new  TodoService(); 
      }
      handleCreate (event)  {
        this.service.create(event);
        this.setState({todos:this.service.todos});
      }
    handleChange(checked,key)   //此處主要是用於處理後端的completed的變化,所以須要傳遞key和對應的觸發事件的值
        {
           console.log(key,checked) //打印key和對應的值
           this.service.todochaService(key,checked) 
        }
      render(){
        return(
            <div>
              <Create onCreate={this.handleCreate.bind(this)} />  {/*本身定義一個屬性,處理props事件的*/}
              {/*完成數據的顯示*/}
              {[...this.service.todos.values()].map( item=> <Todo  onChage={this.handleChange.bind(this)}  key={item.key} todo={item}/>)}  {/*調用todo進行處理相關的函數問題,map後返回新的容器*/}
            </div>
        );
      }
    }
    ReactDOM.render(<Root />,document.getElementById('root'));  //NewRoot(props)  
    // Test(Root)(props)

結果以下

react項目基本實踐

6 過濾查詢實現

建立相關過濾模塊,以下 仍然臨時存儲於src中,建立名爲Filter.js,以下
Filter.js

測試返回結果

import  React  from  'react';
import { Select  } from 'antd';
const { Option } = Select;
import  'antd/lib/select/style';
export default  props  => (
  <Select
    showSearch
    style={{ width: 200 }} defaultValue="uncompleted"  onChange={(event) =>console.log(event)} > 
    <Option value="uncompleted">未完成</Option>
    <Option value="completed">已完成</Option>
    <Option value="all">所有</Option>
  </Select>
);

其中 defaultValue 用於顯示默認設置
onChange={(event) =>console.log(event)} 用於查看選擇引發的調度
<Option value="uncompleted">未完成</Option> 中中間的未完成用於顯示,而value用於實際觸發的傳值。

index.js中添加相關配置以下

import React from 'react';
import ReactDOM from 'react-dom';
import Create  from  './create'
import TodoService  from  './service'
import Todo from './Todo';
import  Filter  from  './filter'
class  Root  extends React.Component {
      constructor (props)  {
        super(props);
        this.service=new  TodoService(); 
      }
      handleCreate (event)  {
        this.service.create(event);
        this.setState({todos:this.service.todos});
      }
    handleChange(checked,key)   //此處主要是用於處理後端的completed的變化,所以須要傳遞key和對應的觸發事件的值
        {
           console.log(key,checked) //打印key和對應的值
           this.service.todochaService(key,checked) 
        }
      render(){
        return(
            <div>
              <Create onCreate={this.handleCreate.bind(this)} />  {/*本身定義一個屬性,處理props事件的*/}
              {/*完成數據的顯示*/}
            <Filter />

              {[...this.service.todos.values()].map( item=> <Todo  onChage={this.handleChange.bind(this)}  key={item.key} todo={item}/>)}  {/*調用todo進行處理相關的函數問題,map後返回新的容器*/}
            </div>
        );
      }
    }
    ReactDOM.render(<Root />,document.getElementById('root'));  //NewRoot(props)  
    // Test(Root)(props)

結果以下

react項目基本實踐

選擇不一樣的選項會致使不一樣的觸發結果,此處即可做爲其條件進行相關操做

配置觸發改變和相關顯示

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Create  from  './create'
import TodoService  from  './service'
import Todo from './Todo';
import  Filter  from  './filter'
class  Root  extends React.Component {
      constructor (props)  {
        super(props);
        this.service=new  TodoService(); 
        this.state={todos:this.service.todos}
        this.state={filter:"uncompleted"}
      }
      handleCreate (event)  {
        this.service.create(event);
        this.setState({todos:this.service.todos});
      }
    handleChange(checked,key)   //此處主要是用於處理後端的completed的變化,所以須要傳遞key和對應的觸發事件的值
        {
           console.log(key,checked) //打印key和對應的值
           this.service.todochaService(key,checked) 
        }
    handleFliter(value){
        this.setState({filter:value})
        this.state.filter=value;  //修改狀態
        console.log(this.state.filter)
    }
      render(){
        return(
            <div>
              <Create onCreate={this.handleCreate.bind(this)} />  {/*本身定義一個屬性,處理props事件的*/}
              {/*完成數據的顯示*/}
              <Filter   onFilter={this.handleFliter.bind(this)}/>
              {[...this.service.todos.values()].filter(item  => {
                    let  fs=this.state.filter;
                    if (fs==="uncompleted")
                        if (item.completed===true)
                            return false  
                        else
                            return true  
                    if  (fs=== "completed") 
                        if (item.completed===true)
                            return  true  
                        else  
                            return  false
                    else 
                        return true
    }).map(item => <Todo  onChage={this.handleChange.bind(this)}  key={item.key} todo={item}/>)}  {/*調用todo進行處理相關的函數問題,map後返回新的容器*/}
            </div>
        );
      }
    }
    ReactDOM.render(<Root />,document.getElementById('root'));  //NewRoot(props)  
    // Test(Root)(props)

修改filter.js以下

import  React  from  'react';
import { Select  } from 'antd';
const { Option } = Select;
import  'antd/lib/select/style';
export default  props  => (
  <Select
    showSearch
    style={{ width: 200 }} defaultValue="uncompleted" onChange={event => props.onFilter(event)}>
    <Option value="uncompleted">未完成</Option>
    <Option value="completed">已完成</Option>
    <Option value="all">所有</Option>
  </Select>
);

結果以下

react項目基本實踐

react項目基本實踐

7 調整代碼佈局

調整代碼佈局,將顯示層(view)代碼調整到component目錄中包括create.js,filter.js,Todo.js和TodoApp.js(此處是將index.js的數據悉數移動到造成的),將後面的service層的代碼調整到service中,以下

react項目基本實踐

index.js 和 TodoApp.js修改以下

TodoApp.js

import React from 'react';
import Create  from  './create'
import TodoService  from  '../service/service'
import Todo from './Todo';
import  Filter  from  './filter'

export  default class  Root  extends React.Component {
      constructor (props)  {
        super(props);
        this.service=new  TodoService(); 
        this.state={todos:this.service.todos}
        this.state={filter:"uncompleted"}
      }
      handleCreate (event)  {
        this.service.create(event);
        this.setState({todos:this.service.todos});
      }
    handleChange(checked,key)   //此處主要是用於處理後端的completed的變化,所以須要傳遞key和對應的觸發事件的值
        {
           console.log(key,checked) //打印key和對應的值
           this.service.todochaService(key,checked) 
        }
    handleFliter(value){
        this.setState({filter:value})
        this.state.filter=value;  //修改狀態
        console.log(this.state.filter)
    }
      render(){
        return(
            <div>
              <Create onCreate={this.handleCreate.bind(this)} />  {/*本身定義一個屬性,處理props事件的*/}
              {/*完成數據的顯示*/}
              <Filter   onFilter={this.handleFliter.bind(this)}/>
              {[...this.service.todos.values()].filter(item  => {
                    let  fs=this.state.filter;
                    if (fs==="uncompleted")
                        if (item.completed===true)
                            return false  
                        else
                            return true  
                    if  (fs=== "completed") 
                        if (item.completed===true)
                            return  true  
                        else  
                            return  false
                    else 
                        return true
    }).map(item => <Todo  onChage={this.handleChange.bind(this)}  key={item.key} todo={item}/>)}  {/*調用todo進行處理相關的函數問題,map後返回新的容器*/}
            </div>
        );
      }
    }

index.js 以下

import ReactDOM from 'react-dom';
import React from 'react';
import  Root  from  './compoent/TodoApp';
ReactDOM.render(<Root />,document.getElementById('root'));  //NewRoot(props)  
    // Test(Root)(props)

8 總結

渲染的事情歸TodoApp負責,並管理全部的狀態。
create負責顯示文本框,接受用戶輸入的待辦事宜。
TOdo,負責每一條數據的顯示和check變化
filter,主要負責一個狀態的filter的切換


service.js

todoservice 負責業務的處理,爲了簡單,把數據處理也放在此處

狀態state的控制和修改有些麻煩,須要改進

三 服務改進

1 狀態監控改進

程序修改

TodoApp觀察TodoService中的變量的變化,如todos。可經過obserable 進行定義被檢查對象,經過 observer 進行檢測處理。


以前的TodoApp是同構service關聯到TodoService實例的,如今修改爲了經過JSX元素屬性的方式傳遞,所以,須要修改index.js和TodoApp及後端。


service.js 修改以下

import  store  from  'store' 
import { observable } from "mobx";

export  default  class TodoService{
    static NAMESPACE="todo"  //定義存儲前綴 
    @observable  todos= new Map();  //定義存儲容器 
    // 建立todo  
    constructor(){
        this.load();
    }
    load(){
        store.each((value,key) => {
            if (key.startsWith(TodoService.NAMESPACE))
                this.todos.set(key,value)
        }
        )} 

    create(title) { //定義函數,用於處理建立和存儲數據
        const todo = {  //定義value類型 
        key: TodoService.NAMESPACE+(new Date()).valueOf(),    /*毫秒時間戳*/
        title :title,  //定義相關類型 
        completed: false //定義數據狀態
        }
        this.todos.set(todo.key,todo);  //存儲至容器中
        //持久化處理
        store.set(todo.key,todo);
        return todo
    }
    todochaService(key,checked){
        let todo=this.todos.get(key)  //獲取對應的值
        todo.completed=checked;  //賦值
        console.log(todo.completed,checked)
        this.todos.set(key,todo) //刷新map
        store.set(key,todo)  //刷新store 
    }
}

index.js修改以下

import ReactDOM from 'react-dom';
import React from 'react';
import  Root  from  './compoent/TodoApp';
import TodoService  from  './service/service'
const  service=new TodoService()

ReactDOM.render(<Root  service={service} />,document.getElementById('root')); //經過外部傳值的方式實現

TodoApp.js以下

import React from 'react';
import Create  from  './create'
import Todo from './Todo';
import  Filter  from  './filter'
import {observer} from 'mobx-react';
@observer
export  default class  Root  extends React.Component {
      constructor (props)  {
        super(props);
        this.state={filter:"uncompleted"}
      }
      handleCreate (event)  {
        this.props.service.create(event); //此處經過index.js的方法進行傳值
      }
    handleChange(checked,key)   //此處主要是用於處理後端的completed的變化,所以須要傳遞key和對應的觸發事件的值
        {
           console.log(key,checked) //打印key和對應的值
           this.props.service.todochaService(key,checked) //此處也是
        }
    handleFliter(value){
        this.setState({filter:value})
        this.state.filter=value;  //修改狀態
        console.log(this.state.filter)
    }
      render(){
        return(
            <div>
              <Create onCreate={this.handleCreate.bind(this)} />  {/*本身定義一個屬性,處理props事件的*/}
              {/*完成數據的顯示*/}
              <Filter   onFilter={this.handleFliter.bind(this)}/>
              {[...this.props.service.todos.values()].filter(item  => { 
                    let  fs=this.state.filter;
                    if (fs==="uncompleted")
                        if (item.completed===true)
                            return false  
                        else
                            return true  
                    if  (fs=== "completed") 
                        if (item.completed===true)
                            return  true  
                        else  
                            return  false
                    else 
                        return true
    }).map(item => <Todo  onChage={this.handleChange.bind(this)}  key={item.key} todo={item}/>)}  {/*調用todo進行處理相關的函數問題,map後返回新的容器*/}
            </div>
        );
      }
    }

2 複選框改變列表不刷新問題

複選框改變列表不刷新問題

運行一切爲正常,就是有一點不方便,及checkbox點擊後,其不會發生重繪操做。


checkbox變化致使了TodoService 的todochaService 函數調用,修改相關屬性,但此處todos並未發生變化,只是修改其內部元素而已,解決方式是手動修改todos,使其發生重繪。

import  store  from  'store' 
import { observable } from "mobx";

export  default  class TodoService{
    static NAMESPACE="todo"  //定義存儲前綴 
    @observable  todos= new Map();  //定義存儲容器 
    // 建立todo  
    constructor(){
        this.load();
    }
    load(){
        store.each((value,key) => {
            if (key.startsWith(TodoService.NAMESPACE))
                this.todos.set(key,value)
        }
        )} 

    create(title) { //定義函數,用於處理建立和存儲數據
        const todo = {  //定義value類型 
        key: TodoService.NAMESPACE+(new Date()).valueOf(),    /*毫秒時間戳*/
        title :title,  //定義相關類型 
        completed: false //定義數據狀態
        }
        this.todos.set(todo.key,todo);  //存儲至容器中
        //持久化處理
        store.set(todo.key,todo);
        return todo
    }
    todochaService(key,checked){
        let todo=this.todos.get(key)  //獲取對應的值
        todo.completed=checked;  //賦值
        console.log(todo.completed,checked)
        this.todos.set(key,todo) //刷新map
        store.set(key,todo)  //刷新store 
        let temp=this.todos;
        this.todos = ()=>{};
        this.todos=temp;
    }

}

結果以下

react項目基本實踐

3 過濾數據方法調整

可以將過濾數據的filter函數後移動到TodoService中。
在TodoService中提供todos屬性的getter,此處可直接將方法當成屬性來調用
相關修改以下

TodoApp.js修改以下

import React from 'react';
import Create  from  './create'
import Todo from './Todo';
import  Filter  from  './filter'
import {observer} from 'mobx-react';
@observer
export  default class  Root  extends React.Component {
      constructor (props)  {
        super(props);
      }
      handleCreate (event)  {
        this.props.service.create(event);
      }
    handleChange(checked,key)   //此處主要是用於處理後端的completed的變化,所以須要傳遞key和對應的觸發事件的值
        {
           console.log(key,checked) //打印key和對應的值
           this.props.service.todochaService(key,checked) 
        }
    handleFliter(value){
        this.props.service.setFilterState(value)
    }
      render(){
        return(
            <div>
              <Create onCreate={this.handleCreate.bind(this)} />  {/*本身定義一個屬性,處理props事件的*/}
              {/*完成數據的顯示*/}
              <Filter   onFilter={this.handleFliter.bind(this)}/>
              {this.props.service.todos.map(item => <Todo  onChage={this.handleChange.bind(this)}  key={item.key} todo={item}/>)}
            </div>
        );
      }
    }

修改代碼以下

service.js修改以下

import  store  from  'store' 
import { observable,computed } from "mobx";

export  default  class TodoService{
    static NAMESPACE="todo"  //定義存儲前綴 
    @observable  _todos= new Map();  //定義存儲容器 
    @observable  filter="uncompleted"  //此處定義filter
    setFilterState(value){
                this.filter = value;  //須要修改此處
            }
    @computed  //此處會加快響應速率
    get todos(){
        return  [...this._todos.values()]
        .filter(item  => {
            let  fs=this.filter;
            if (fs==="uncompleted")
                if (item.completed===true)
                    return false  
                else
                    return true  
            if  (fs=== "completed") 
                if (item.completed===true)
                    return  true  
                else  
                    return  false
            else 
                return true
        });
    }

    // 建立todo  
    constructor(){
        this.load();
    }
    load(){
        store.each((value,key) => {
            if (key.startsWith(TodoService.NAMESPACE))
                this._todos.set(key,value)
        }
        )} 

    create(title) { //定義函數,用於處理建立和存儲數據
        const todo = {  //定義value類型 
        key: TodoService.NAMESPACE+(new Date()).valueOf(),    /*毫秒時間戳*/
        title :title,  //定義相關類型 
        completed: false //定義數據狀態
        }
        this._todos.set(todo.key,todo);  //存儲至容器中
        //持久化處理
        store.set(todo.key,todo);
        return todo
    }
    todochaService(key,checked){
        let todo=this._todos.get(key)  //獲取對應的值
        todo.completed=checked;  //賦值
        console.log(todo.completed,checked)
        this._todos.set(key,todo) //刷新map
        store.set(key,todo)  //刷新store 
        let temp=this._todos;
        this._todos = ()=>{};
        this._todos=temp;
    }   
}

4 處理輸入待辦事宜自動刷新問題

import  store  from  'store' 
import { observable,computed } from "mobx";

export  default  class TodoService{
    static NAMESPACE="todo"  //定義存儲前綴 
    @observable  _todos= new Map();  //定義存儲容器 
    @observable  filter="uncompleted"  //此處定義filter
    setFilterState(value){
                this.filter = value;  //須要修改此處
            }
    @computed
    get todos(){
        return  [...this._todos.values()]
        .filter(item  => {
            let  fs=this.filter;
            if (fs==="uncompleted")
                if (item.completed===true)
                    return false  
                else
                    return true  
            if  (fs=== "completed") 
                if (item.completed===true)
                    return  true  
                else  
                    return  false
            else 
                return true
        });
    }
    flush (){  //強制刷新步驟
        let temp=this._todos;
        this._todos = ()=>{};
        this._todos=temp;
    }
    // 建立todo  
    constructor(){
        this.load();
    }
    load(){
        store.each((value,key) => {
            if (key.startsWith(TodoService.NAMESPACE))
                this._todos.set(key,value)
        }
        )} 

    create(title) { //定義函數,用於處理建立和存儲數據
        const todo = {  //定義value類型 
        key: TodoService.NAMESPACE+(new Date()).valueOf(),    /*毫秒時間戳*/
        title :title,  //定義相關類型 
        completed: false //定義數據狀態
        }
        this._todos.set(todo.key,todo);  //存儲至容器中
        //持久化處理
        store.set(todo.key,todo);
        this.flush();
        return todo
    }
    todochaService(key,checked){
        let todo=this._todos.get(key)  //獲取對應的值
        todo.completed=checked;  //賦值
        console.log(todo.completed,checked)
        this._todos.set(key,todo) //刷新map
        store.set(key,todo)  //刷新store 
        this.flush()
    }   
}

四 部署相關事宜

1 編寫python端配置,及後端服務配置

1 安裝模塊

pip install  aiohttp

2 編寫代碼

#!/usr/bin/poython3.6
#conding:utf-8
from  aiohttp  import  web,log
import logging
import  json

async  def  indexhandle(request:web.Request):
    return   web.Response(text='welcom  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)

    js=await  request.json() #協程是一個一個迭代,獲取json字符串提交數據
    print (js,type(js))

    text=dict(await request.post()) #此處是一個可迭代對象,傳統post提交//postman中使用此種方式進行提交處>理的
    print (text,type(text))

    js.update(text) #字典的合併  {}.update(**js,**text)
    res=json.dumps(js)  #json化,將其轉換成python的字符串
    print  (res)

    return  web.Response(text=res,status=201)

app=web.Application()
app.router.add_get('/',indexhandle)
app.router.add_get('/{id}',handle)
app.router.add_post('/todo',todopost)

app.logger.setLevel(level=logging.NOTSET)  #最底級別
web.run_app(app,host='0.0.0.0',port=8080)

3 啓動以下

python  test.py   &

4 結果以下

react項目基本實踐

2 前端

1 查看後端IP地址和相關監聽端口

本機服務器端IP地址爲192.168.1.200,監聽端口爲8080

react項目基本實踐

2 修改webpack.config.dev.js 相關反響代理端配置以下

react項目基本實踐

3 重啓訪問以下

訪問跟根

react項目基本實踐

訪問id

react項目基本實踐

訪問todo,上述只支持JSON格式,其餘格式訪問則不能正常訪問

react項目基本實踐

相關文章
相關標籤/搜索