react入門系列之使用 antd, react, redux,creat-react-app搭建todo-list升級版本

### redux簡介

- redux是一個配合react視圖層框架使用的數據層框架
- 方便大型react項目之中的複雜組件傳值
- 耦合性高的數據使用redux管理
- redux中包含 組件,store,reducer
- 1. store必須是惟一的,整個項目之中只能有一個數據存儲空間
- 2. store中的數據是store本身更新的,並非reducer,這也是爲何reducer中不能直接改變state中的數據
- 3. Reducer必須是個純函數。
-   3.1 純函數: 是給定固定的輸入,就必定會有固定的輸出。並且不能有任何的反作用(不能對參數進行修改)

#### redux數據流向

- store就像一個圖書管理員
- 圖書管理員會給每一個須要借書的人發一個通信工具(store)
- 通信工具store有一個方法叫作subscribe(),每當圖書館的圖書有變化,這個方法就會自動執行
- 通信工具store提供一個getState()方法,方便借書人立馬獲得最新的圖書館數據,配合subscribe()使用
- 通信工具store提供一個dispatch()方法,方便借書人傳達他想借閱的書籍名稱
- reducer是圖書管理員的查詢手冊
- 他是圖書管理員的查詢手冊,當圖書管理員接到借書人的消息後,他會查閱reducer
- 圖書館管理員也是經過查詢手冊肯定數據的更新
- 查詢手冊返回的是一個方法,這個方法有2個參數(state,action)
- state就是圖書館數據,action是借書人經過store傳遞過來的參數,也就是書名,經過action,查詢手冊才能查詢到數據
- reducer返回的方法不能直接更改state
- 組件就像借書人
- 借書人須要借書,經過圖書管理員提供的通信工具store提供的dispatch方法,傳達他要借的書(action)
- 借書人經過圖書管理員提供的通信工具store提供的subscribe()和getState()獲取圖書管的最新諮詢

### 建立項目

- create-react-app todo-list
- 注意項目名稱不能有大寫字母

### 刪除沒必要要文件

- src目錄中的:App.css, App.test.js, logo.svg, serviceWorker.js文件
- public目錄中的: manifest.json文件

 

### 安裝依賴

- yarn add antd
- yarn add redux

### 入口index.js編寫

1 import React from 'react';
2 import ReactDOM from 'react-dom';
3 import App from './App'; // 引入萬年老二組件
4 
5 ReactDOM.render(<App />, document.getElementById('root'));
 

### 建立redux的store

- index.js

 1 /**
 2 * store就像一個圖書管理員,在接到組件(借書人)派發的 dispatch(借書人說的話) 時,
 3 * 他自己不知道書在什麼位置,有沒有這本書,須要查詢 reducer (圖書列表)
 4 */
 5 import { createStore } from 'redux'
 6 import todoListReducer from './reducer' // 引入圖書列表
 7 
 8 
 9 const store = createStore(todoListReducer) // 查詢圖書列表
10 
11 
12 export default store

- reducer.js

 1 /**
 2 * reducer 至關於圖書管理員 store 的查詢手冊,
 3 * 經過查詢手冊,確認組件 借書人人須要的書在什麼地方。
 4 */
 5 const todoState = {
 6 inputValue : "",
 7 list: []
 8 }
 9 
10 export default (state=todoState, action) => {
11 if ( action.type === 'change_input_value'){ // 確認書名, 執行動做
12 const newState = JSON.parse(JSON.stringify(state))
13 newState.inputValue = action.value
14 console.log(newState)
15 return newState
16 }
17 if ( action.type === 'change_list_value'){ // 確認書名, 執行動做
18 const newState = JSON.parse(JSON.stringify(state))
19 newState.list = [...state.list, action.item]
20 newState.inputValue = ''
21 console.log(newState.list)
22 return newState
23 }
24 return state
25 }

 

 

### 編寫html結構

- 在App.js中引入所需依賴
- 1. antd的樣式
- 2. antd的組件
- 3. react
- 4. store
 1 /**
 2 * 組件就是一個須要借書的人,經過 dispatch 傳達 action (書名)給圖書管理員(store)
 3 */
 4 /**
 5 * 組件就是一個須要借書的人,經過 dispatch 傳達 action (書名)給圖書管理員(store)
 6 */
 7 
 8 /**
 9 * 組件就是一個須要借書的人,經過 dispatch 傳達 action (書名)給圖書管理員(store)
10 */
11 
12 import React, { Component, Fragment }from 'react';
13 import { Input, Button, List, message } from "antd";
14 import store from './store'; // 引入圖書管理員 store
15 import "antd/dist/antd.css";
16 class App extends Component {
17 constructor(props){
18 super(props)
19 this.state = store.getState()
20 console.log(store.getState())
21 this.handleInputChange = this.handleInputChange.bind(this);
22 this.addTodoList = this.addTodoList.bind(this);
23 this.handleStroeChange = this.handleStroeChange.bind(this);
24 // this.deletTodoList = this.deletTodoList.bind(this);
25 store.subscribe(this.handleStroeChange) // 圖書管理員會隨時通知各個借書人,圖書館書籍的變化
26 }
27 
28 render() {
29 return (
30 <Fragment>
31 <div style={{ marginTop: '10px', marginLeft: '10px'}}>
32 <Input
33 placeholder='todo-list'
34 style={{width: '300px', marginRight: '10px'}}
35 onChange = { this.handleInputChange }
36 value = { this.state.inputValue }
37 />
38 <Button
39 type="primary"
40 onClick = { this.addTodoList }
41 >提交</Button>
42 </div>
43 <List
44 style={{width: '300px', marginLeft: '10px', marginTop: '5px'}}
45 size="large"
46 bordered
47 dataSource={ this.state.list ? this.state.list : null }
48 renderItem={ (item, index) => <List.Item style={{position:'relative'}}>
49 {item}
50 <Button
51 type='danger'
52 style={{position: 'absolute', right: '10px', top:'50%', marginTop:'-5%'}}
53 onClick={ this.deletTodoList.bind(this, index) }
54 >刪除</Button>
55 </List.Item>}
56 />
57 </Fragment>
58 );
59 }
60 handleInputChange(e) {
61 const action = {
62 type: 'change_input_value', // 借什麼書
63 value: e.target.value
64 }
65 store.dispatch(action); // 傳達給store
66 console.log(e.target.value)
67 }
68 addTodoList() {
69 if (this.state.inputValue) {
70 const action = {
71 type: 'change_list_value',
72 item: this.state.inputValue
73 }
74 store.dispatch(action)
75 } else {
76 message.warning('請輸入內容');
77 }
78 }
79 deletTodoList(index) {
80 const action = {
81 type: 'delet_list_value',
82 value: index
83 }
84 store.dispatch(action)
85 }
86 handleStroeChange() {
87 this.setState(store.getState()) // 每當圖書館有變化的時候,圖書管理員(store)經過這個方式告訴借書人(組件)
88 }
89 }
90 
91 export default App;

### ActionType的拆分

- 咱們在組件中建立action的時候,配置type等於一個字符串,在reducer中判斷action.type的時候,容易出錯,而且出錯也不會報錯。
- 因此咱們須要將ActionType作一個拆分
- 在store中新建一個actionTypes.js文件
1 export const CHANGE_INPUT_VALUE = 'change_input_value'
2 export const CHANGE_LIST_VALUE = 'change_list_value'
3 export const DELETE_LIST_VALUE = 'delet_list_value'
- 在須要使用的組件中,以及reducer中導入替換到原來的字符串
  1 /**
  2  * reducer 至關於圖書管理員 store 的查詢手冊,
  3  * 經過查詢手冊,確認組件 借書人人須要的書在什麼地方。
  4  */
  5 
  6 import { CHANGE_INPUT_VALUE, CHANGE_LIST_VALUE, DELETE_LIST_VALUE } from './actionTypes'
  7 const todoState = {
  8     inputValue : "",
  9     list: []
 10 }
 11 
 12 export default (state=todoState, action) => {
 13     if ( action.type === CHANGE_INPUT_VALUE){ // 確認書名, 執行動做
 14         const newState = JSON.parse(JSON.stringify(state))
 15         newState.inputValue = action.value
 16         console.log(newState)
 17         return newState
 18     }
 19     if ( action.type === CHANGE_LIST_VALUE){ // 確認書名, 執行動做
 20         const newState = JSON.parse(JSON.stringify(state))
 21         newState.list = [...state.list, action.item]
 22         newState.inputValue = ''
 23         console.log(newState.list)
 24         return newState
 25     }
 26     if ( action.type === DELETE_LIST_VALUE){
 27         const newState = JSON.parse(JSON.stringify(state))
 28         console.log(action.value)
 29         newState.list.splice(action.value, 1)
 30         return newState
 31     }
 32     return state
 33 }
 34 
 35 
 36 // --------------------------------分割線---------------------------------
 37 
 38 
 39 /**
 40  * 組件就是一個須要借書的人,經過 dispatch 傳達 action (書名)給圖書管理員(store)
 41  */
 42 
 43 import React, { Component, Fragment }from 'react';
 44 import { Input, Button, List, message } from "antd";
 45 import store from './store'; // 引入圖書管理員 store
 46 import { CHANGE_INPUT_VALUE, CHANGE_LIST_VALUE, DELETE_LIST_VALUE } from './store/actionTypes'
 47 import "antd/dist/antd.css";
 48 class App extends Component {
 49   constructor(props){
 50     super(props)
 51     this.state = store.getState()
 52     console.log(store.getState())
 53     this.handleInputChange = this.handleInputChange.bind(this);
 54     this.addTodoList = this.addTodoList.bind(this);
 55     this.handleStroeChange = this.handleStroeChange.bind(this);
 56     // this.deletTodoList = this.deletTodoList.bind(this);
 57     store.subscribe(this.handleStroeChange) // 圖書管理員會隨時通知各個借書人,圖書館書籍的變化
 58   }
 59 
 60   render() {
 61     return (
 62       <Fragment>
 63         <div style={{ marginTop: '10px', marginLeft: '10px'}}>
 64           <Input 
 65           placeholder='todo-list'
 66           style={{width: '300px', marginRight: '10px'}}
 67           onChange = { this.handleInputChange }
 68           value = { this.state.inputValue }
 69           />
 70           <Button 
 71           type="primary"
 72           onClick = { this.addTodoList }
 73           >提交</Button>
 74         </div>
 75         <List
 76         style={{width: '300px', marginLeft: '10px', marginTop: '5px'}}
 77         size="large"
 78         bordered
 79         dataSource={ this.state.list ? this.state.list : null }
 80         renderItem={ (item, index) => <List.Item style={{position:'relative'}}>
 81         {item}
 82         <Button 
 83         type='danger' 
 84         style={{position: 'absolute', right: '10px', top:'50%', marginTop:'-5%'}}
 85         onClick={ this.deletTodoList.bind(this, index) }
 86         >刪除</Button>
 87         </List.Item>}
 88         />
 89       </Fragment>
 90     );
 91   }
 92   handleInputChange(e) {
 93     const action = {
 94       type: CHANGE_INPUT_VALUE, // 借什麼書
 95       value: e.target.value
 96     }
 97     store.dispatch(action); // 傳達給store
 98     console.log(e.target.value)
 99   }
100   addTodoList() {
101     if (this.state.inputValue) {
102       const action = {
103         type: CHANGE_LIST_VALUE,
104         item: this.state.inputValue
105       }
106       store.dispatch(action)
107     } else {
108       message.warning('請輸入內容');
109     }
110   }
111   deletTodoList(index) {
112     const action = {
113       type: DELETE_LIST_VALUE,
114       value: index
115     }
116     store.dispatch(action)
117   }
118   handleStroeChange() {
119     this.setState(store.getState()) // 每當圖書館有變化的時候,圖書管理員(store)經過這個方式告訴借書人(組件)
120   }
121 }
122 
123 export default App;

###使用actionCreators統一建立action

- 以前咱們建立的action,都是在組件中建立的,可是若是是大型的,邏輯複雜的項目這樣寫不方便前端測試,也不利於維護
- 所以,咱們須要將action統一在一個地方建立
- 在store文件夾中建立一個actionCreators.js,專門用來建立action
- 而且,要在actionCreators中引入咱們以前actionTypes.js。
- 而後在須要使用action的組件按需求引入便可
  1 /**
  2  * 其實就是返回一個能獲取action的方法
  3  * actionCreators.js
  4 */
  5 import { CHANGE_INPUT_VALUE, CHANGE_LIST_VALUE, DELETE_LIST_VALUE } from './actionTypes'
  6 
  7 export const getInputChangeValue = (value) => ({
  8     type: CHANGE_INPUT_VALUE,
  9     value
 10 })
 11 
 12 export const getAddTodoListValue = (item) => ({
 13     type: CHANGE_LIST_VALUE,
 14     item
 15 })
 16 
 17 export const getDeletTodoListValue = (index) => ({
 18     type: DELETE_LIST_VALUE,
 19     index
 20 })
 21 
 22 // -----------------分割線--------------------------
 23 
 24 /**
 25  * App.js
 26  * 在組件中引用action
 27  * 此處省略了無關代碼,能夠參照上面的代碼
 28 */
 29 /**
 30  * 組件就是一個須要借書的人,經過 dispatch 傳達 action (書名)給圖書管理員(store)
 31  */
 32 
 33 import React, { Component, Fragment }from 'react';
 34 import { Input, Button, List, message } from "antd";
 35 import store from './store'; // 引入圖書管理員 store
 36 // 引入action
 37 import { getInputChangeValue, getAddTodoListValue, getDeletTodoListValue } from './store/actionCreators'
 38 // import { CHANGE_INPUT_VALUE, CHANGE_LIST_VALUE, DELETE_LIST_VALUE } from './store/actionTypes'
 39 import "antd/dist/antd.css";
 40 class App extends Component {
 41   constructor(props){
 42     super(props)
 43     this.state = store.getState()
 44     console.log(store.getState())
 45     this.handleInputChange = this.handleInputChange.bind(this);
 46     this.addTodoList = this.addTodoList.bind(this);
 47     this.handleStroeChange = this.handleStroeChange.bind(this);
 48     // this.deletTodoList = this.deletTodoList.bind(this);
 49     store.subscribe(this.handleStroeChange) // 圖書管理員會隨時通知各個借書人,圖書館書籍的變化
 50   }
 51 
 52   render() {
 53     return (
 54       <Fragment>
 55         <div style={{ marginTop: '10px', marginLeft: '10px'}}>
 56           <Input 
 57           placeholder='todo-list'
 58           style={{width: '300px', marginRight: '10px'}}
 59           onChange = { this.handleInputChange }
 60           value = { this.state.inputValue }
 61           />
 62           <Button 
 63           type="primary"
 64           onClick = { this.addTodoList }
 65           >提交</Button>
 66         </div>
 67         <List
 68         style={{width: '300px', marginLeft: '10px', marginTop: '5px'}}
 69         size="large"
 70         bordered
 71         dataSource={ this.state.list ? this.state.list : null }
 72         renderItem={ (item, index) => <List.Item style={{position:'relative'}}>
 73         {item}
 74         <Button 
 75         type='danger' 
 76         style={{position: 'absolute', right: '10px', top:'50%', marginTop:'-5%'}}
 77         onClick={ this.deletTodoList.bind(this, index) }
 78         >刪除</Button>
 79         </List.Item>}
 80         />
 81       </Fragment>
 82     );
 83   }
 84   handleInputChange(e) {
 85     /*
 86     const action = {
 87       type: CHANGE_INPUT_VALUE, // 借什麼書
 88       value: e.target.value
 89     }
 90     */
 91     const action = getInputChangeValue(e.target.value)
 92     store.dispatch(action); // 傳達給store
 93     console.log(e.target.value)
 94   }
 95   // 添加
 96   addTodoList() {
 97     /*
 98     if (this.state.inputValue) {
 99       const action = {
100         type: CHANGE_LIST_VALUE,
101         item: this.state.inputValue
102       }
103       store.dispatch(action)
104     } else {
105       message.warning('請輸入內容');
106     }
107     */
108    if (this.state.inputValue) {
109       const action = getAddTodoListValue(this.state.inputValue)
110       store.dispatch(action)
111    } else {
112     message.warning('請輸入內容');
113    }
114   }
115   // 刪除
116   deletTodoList(index) {
117     /*
118     const action = {
119       type: DELETE_LIST_VALUE,
120       value: index
121     }
122     */
123     const action = getDeletTodoListValue(index)
124     store.dispatch(action)
125   }
126   handleStroeChange() {
127     this.setState(store.getState()) // 每當圖書館有變化的時候,圖書管理員(store)經過這個方式告訴借書人(組件)
128   }
129 }
130 
131 export default App;
相關文章
相關標籤/搜索