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;

 

转载于:https://www.cnblogs.com/boye-1990/p/11453246.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值