源码地址
https://github.com/Hard-workingrookie/react-redux-todolist
react-redux编写TodoList
React-Redux介绍和安装
React-Redux 是react生态中的常用组件,可以理解为全局数据状态管理工具(状态管理机),用来做组件通信等。
react项目初始化
1 2 3 4
| create-react-app demo02 cd demo02 npm start
|
或者
安装完成后,删除一些没有必要的样式和代码,在/src目录下,只留一个index.js文件,其余的全部删除,这时候项目已经不能启动起来了,这很正常。
1 2 3 4
| import React from 'react'; import ReactDOM from 'react-dom'; ReactDOM.render(<App />, document.getElementById('root'));
|
我们把APP删除了,所以会报错,不过没有关系,我们之后再来处理这个。
react-redux
项目初始化好后,直接使用npm在命令行安装React-redux,这个网络的不同安装时间也有所不同。
1
| npm install --save react-redux
|
或者
1
| yarn add react-redux --save
|
修改代码,跑起来
建立一个TodoList.js的组件
1 2 3 4 5 6 7 8
| import React, { Component } from 'react'; class TodoList extends Component { render() { return ( <div>LitterWang</div> ); } } export default TodoList;
|
将TodoList.js引入到index.js文件下:
1 2 3 4
| import React from 'react'; import ReactDOM from 'react-dom'; import TodoList from './TodoList' ReactDOM.render(<TodoList />, document.getElementById('root'));
|
这时候再在浏览器中预览,就会只输出一个LitterWang的字样。虽然很丑,但是项目已经跑起来了。接下来我们编写一下render函数中的JSX页面。
1 2 3 4 5 6 7 8 9 10
| render() { return ( <div> <div><input /><button>提交</button></div> <ul> <li>LitterWang</li> </ul> </div> ); }
|
这时候界面应该发生了一点变化,这样基本的项目我们就算初始化完成了,接下来我们按原来的Redux方式作一个store出来。
Redux 的安装和使用(复习)
先在终端中安装Redux包,因为是一个新项目,所以需要重新安装。
1 2 3
| npm install --save redux 或 yarn add redux --save
|
创建一个store文件夹,在/store下创建一个index.js文件,并写入下面代码:
1 2 3 4 5 6 7
| import {createStore} from 'redux' import reducer from './reducer'
const store = createStore(reducer)
export default store
|
创建reducer.js文件,代码如下:
1 2 3 4 5 6 7 8
| const defalutState = { inputValue : 'LitterWang', list :[] }
export default (state = defalutState,action) =>{ return state }
|
然后再TodoList.js中的构造函数constructor中使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import React, { Component } from 'react';
import store from './store'
class TodoList extends Component { constructor(props){ super(props) this.state = store.getState() } render() { return ( <div> <div> <input value={this.state.inputValue} /> <button>提交</button> </div> <ul> <li>JSPang</li> </ul> </div> ); } }
export default TodoList;
|
写完这段,到浏览器中保存看一下,应该就得到store中的值了,到目前为止,我们只是安装了React-Redux,但是还并没有进行使用,这节课只要是把基本的环境搭建好和复习一下以前的知识。下节课我们再逐步学习React-Redux的知识,小伙伴们先不要着急,先把开发环境搭建好吧。
Provider和connect
上节课已经完成了React-redux开发TodoList组件的基本环境。现在就可以开心的学习React-redux了,这节课主要学习一下Provider和connect这两个知识点。
Provider 提供器
是一个提供器,只要使用了这个组件,组件里边的其它所有组件都可以使用store了,这也是React-redux的核心组件了。有了就可以把/src/index.js改写成下面的代码样式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import React from 'react'; import ReactDOM from 'react-dom'; import TodoList from './TodoList'
import { Provider } from 'react-redux' import store from './store'
const App = ( <Provider store={store}> <TodoList /> </Provider> )
ReactDOM.render(App, document.getElementById('root'));
|
完这个,我们再去浏览器中进行查看,发现代码也是可以完美运行的。需要注意的是,现在还是用传统方法获取的store中的数据。有了Provider再获取数据就没有那么麻烦了。
connect 连接器
现在如何简单的获取store中数据那?先打开TodoList.js文件,引入connect,它是一个连接器(其实它就是一个方法),有了这个连接器就可以很容易的获得数据了。
1
| import {connect} from 'react-redux'
|
这时候暴露出去的就变成了connect了,代码如下。
1
| export default connect(xxx,null)(TodoList);
|
这里的xxx代表一个映射关系,目前还没有制作这个映射关系。
映射关系的制作
映射关系就是把原来的state映射成组件中的props属性,比如我们想映射inputValue就可以写成如下代码。
1 2 3 4 5
| const stateToProps = (state)=>{ return { inputValue : state.inputValue } }
|
这时候再把xxx改为stateToProps
1
| export default connect(stateToProps,null)(TodoList)
|
然后把input里的state标签,改为props,代码如下:
1
| <input value={this.props.inputValue} />
|
为了方便你学习,我这里给出所有的TodoList.js的所有代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import React, { Component } from 'react'; import store from './store' import {connect} from 'react-redux'
class TodoList extends Component { constructor(props){ super(props) this.state = store.getState() } render() { return ( <div> <div> <input value={this.props.inputValue} /> <button>提交</button> </div> <ul> <li>JSPang</li> </ul> </div> ); } }
const stateToProps = (state)=>{ return { inputValue : state.inputValue } }
export default connect(stateToProps,null)(TodoList);
|
写完之后再到浏览器中查看一下,发现我们映射的关系也是可以用的。这节课就是React-Redux插件的使用重点,你需要多写几遍,把这个流程记在心里。先到这里,下节课我们继续实现TodoList组件
React-redux的数据修改
上节课已经可以用React-redux顺利的拿到Store中数据了。这节课学习如何改变Store中的数据。也就是当我们修改 input 中的值时,去改变store数据,UI界面也随之进行改变。
编写 onChange 响应事件
打开TodoList.js文件,然后在 button 上注册onChange事件,这里我就偷懒直接绑定this了。
1
| <input value={this.props.inputValue} onChange={this.inputChange.bind(this)} />
|
有了事件需要编写对应的方法,这里先写一个最简单的inputChange方法。
1 2 3
| inputChange(e){ console.log(e.target.value) }
|
然后到浏览器中的控制台就不再有报错,而且输入时可以打印出值,这书名我们的绑定成功了。这步完成我们要改为react-redux的了。
编写DispatchToProps
要使用react-redux,我们可以编写另一个映射DispatchToProps,先看下面这段代码,你会发现有两个参数,第二个参数我们用的是null。
1 2 3 4 5 6 7 8 9 10
| export default connect(stateToProps,null)(TodoList); DispatchToProps就是要传递的第二个参数,通过这个参数才能改变store中的值。
const dispatchToProps = (dispatch) =>{ return { inputChange(e){ console.log(e.target.value) } } }
|
有了这个参数之后可以把响应事件改成下面的代码.
1
| <input value={this.props.inputValue} onChange={this.props.inputChange} />
|
然后把connect第二个参数传递过去。
1
| export default connect(stateToProps,dispatchToProps)(TodoList);
|
这时候原来的inputChange方法就没用了,可以删除掉。 目前整体的代码就改为下面的样子了,我们在浏览器中预览也是可以看到效果的。此步骤成功说明映射关系支持成功。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import React, { Component } from 'react'; import store from './store' import {connect} from 'react-redux'
class TodoList extends Component { constructor(props){ super(props) this.state = store.getState() } render() { return ( <div> <div> <input value={this.props.inputValue} onChange={this.props.inputChange} /> <button>提交</button> </div> <ul> <li>JSPang</li> </ul> </div> ); } } const stateToProps = (state)=>{ return { inputValue : state.inputValue } }
const dispatchToProps = (dispatch) =>{ return { inputChange(e){ console.log(e.target.value) } } }
export default connect(stateToProps,dispatchToProps)(TodoList);
|
派发action到store中
映射关系已经做好了,接下来只要进行action的派发和reducer对业务逻辑的编写就可以了。派发action和以前的流程一样,我就直接给出代码了。
1 2 3 4 5 6 7 8 9 10 11
| const dispatchToProps = (dispatch) =>{ return { inputChange(e){ let action = { type:'change_input', value:e.target.value } dispatch(action) } } }
|
派发后就需求在reducer里边,编写对应的业务逻辑了。
1 2 3 4 5 6 7 8 9 10 11 12
| const defalutState = { inputValue : 'jspang', list :[] } export default (state = defalutState,action) =>{ if(action.type === 'change_input'){ let newState = JSON.parse(JSON.stringify(state)) newState.inputValue = action.value return newState } return state }
|
这样就算整个修改过程完成了,到浏览器中查看一下,应该就实现了改变input框的效果。这个流程你刚开始学会觉的很绕,但是你作的多了,你就会发现它很简单,就是一个模式,而且会降低程序出错的机率。建议这个流程你至少要写5遍以上,据我所知,几乎所有公司用react都会用到react-redux,所以这个流程重要性不次于Redux的流程,一定要熟练掌握。
进阶 React-redux增加List数据
点击提交按钮时,可以在列表中进行增加。给 button 按钮增加点击事件 ,直接在/src/TodoList.js里的Button增加一个onClick事件,代码如下:
1
| <button onClick={this.props.clickButton}>提交</button>
|
注意这里依然使用的props,也就是说还需要把方法写在dispatchToProps里。我们这里先写一个测试,看看是否绑定上了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const dispatchToProps = (dispatch) =>{ return { inputChange(e){ let action = { type:'change_input', value:e.target.value } dispatch(action) }, clickButton(){ console.log('111111111') } } }
|
写完clickButton方法后,在浏览器中预览,打开浏览器的控制台看一下结果,应该在点击时,可以看到显示111111111。 这步完成,就是用dispatch派发action了。
1 2 3 4
| clickButton(){ let action = { type:'add_item' } dispatch(action) }
|
编写Reducer的业务逻辑,派发完成后,到Reducer编写业务逻辑,这一步和一起的操作基本一样。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const defalutState = { inputValue : 'jspang', list :[] }
export default (state = defalutState,action) =>{ if(action.type === 'change_input'){ let newState = JSON.parse(JSON.stringify(state)) newState.inputValue = action.value return newState } if(action.type === 'add_item'){ let newState = JSON.parse(JSON.stringify(state)) newState.list.push(newState.inputValue) newState.inputValue = '' return newState } return state }
|
页面UI部分的制作
这步完成后,我们到TodoList.js中进行JSX部分的编写,编写前需要先把stateToProps的映射关系做好。
1 2 3 4 5 6 7
| const stateToProps = (state)=>{ return { inputValue : state.inputValue, list:state.list } }
|
有了映射关系,就可以再界面中用属性的方式,进行显示,代码如下:
1 2 3 4 5 6 7 8
| <ul> { this.props.list.map((item,index)=>{ return (<li key={index}>{item}</li>) }) } </ul>
|
这样就实现了增加TodoList的列表项,这里给出TodoList.js的代码.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| import React, { Component } from 'react'; import store from './store' import {connect} from 'react-redux'
class TodoList extends Component { constructor(props){ super(props) this.state = store.getState() } render() { return ( <div> <div> <input value={this.props.inputValue} onChange={this.props.inputChange} /> <button onClick={this.props.clickButton}>提交</button> </div> <ul> { this.props.list.map((item,index)=>{ return (<li key={index}>{item}</li>) }) } </ul> </div> ); } } const stateToProps = (state)=>{ return { inputValue : state.inputValue, list:state.list } }
const dispatchToProps = (dispatch) =>{ return { inputChange(e){ let action = { type:'change_input', value:e.target.value } dispatch(action) }, clickButton(){ let action = { type:'add_item' } dispatch(action) } } } export default connect(stateToProps,dispatchToProps)(TodoList);
|
还有一个删除功能我就不浪费大家时间继续制作了,如果你自己有兴趣可以试着作一下。
加餐-React-redux程序优化(完结)
这节课把现在写的代码优化一下,作程序的都应该有一些代码洁癖,才能写出让人称赞的程序。写完业务逻辑后作代码优化,也是程序员的本质工作之一。 现在代码中有好几处this.props都是重复的,这时候就可以用javascript的解构赋值方法,来精简代码。修改TodoList.js中的Render函数,把原来带代码修改为下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| render() { let {inputValue ,inputChange,clickButton,list} = this.props; return ( <div> <div> <input value={inputValue} onChange={inputChange} /> <button onClick={clickButton}>提交</button> </div> <ul> { list.map((item,index)=>{ return (<li key={index}>{item}</li>) }) } </ul> </div> ); }
|
把TodoList改为UI组件-提高性能
可以看到,现在的TodoList组件里没有任何的业务逻辑,只有一个Render方法,这时候就可以把它改为UI组件(无状态组件),UI组件就是一个方法,减少很多冗余操作,从而提高程序运行性能。这时候重新声明一个TodoList的变量,然后把render函数里的东西复制过来,只要稍加修改,就可以得到下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const TodoList =(props)=>{ let {inputValue ,inputChange,clickButton,list} = props; return ( <div> <div> <input value={inputValue} onChange={inputChange} /> <button onClick={clickButton}>提交</button> </div> <ul> { list.map((item,index)=>{ return (<li key={index}>{item}</li>) }) } </ul> </div> ); }
|
代码写完后,我们删除一些不用的引入,然后就可以到浏览器中进行预览了。
1 2 3 4
| import React from 'react'; import {connect} from 'react-redux'
|
目前TodoList.js的所有代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| import React from 'react'; import {connect} from 'react-redux'
const TodoList =(props)=>{ let {inputValue ,inputChange,clickButton,list} = props; return ( <div> <div> <input value={inputValue} onChange={inputChange} /> <button onClick={clickButton}>提交</button> </div> <ul> { list.map((item,index)=>{ return (<li key={index}>{item}</li>) }) } </ul> </div> ); }
const stateToProps = (state)=>{ return { inputValue : state.inputValue, list:state.list } }
const dispatchToProps = (dispatch) =>{ return { inputChange(e){ let action = { type:'change_input', value:e.target.value } dispatch(action) }, clickButton(){ let action = { type:'add_item' } dispatch(action) } } } export default connect(stateToProps,dispatchToProps)(TodoList);
|
那我们反过来,再来理解一下最后一句话代码的意思。
1
| export default connect(stateToProps,dispatchToProps)(TodoList);
|
connect的作用是把UI组件(无状态组件)和业务逻辑代码的分开,然后通过connect再链接到一起,让代码更加清晰和易于维护。这也是React-Redux最大的有点。Redux的教程和视频到这里就结束了,下套课程我会讲解React-router,请小伙伴们持续关注博客.
redux和react-redux关系图
图片转载于https://blog.csdn.net/qq_42767631/article/details/83096841