一、引子
今天利用一个小案例完成对redux的知识回顾。首先看效果(完整代码见文末):
完成功能:
1.利用redux完成加1、减1、加任意值、异步加1
2.实现两个组件间的数据共享
3.一些代码优化
二、redux版
首先建立src文件夹如下结构(示例):
创建store:
//store/index.js
// 1.引入createStore
//applyMiddleware在异步操作时使用
import {createStore,applyMiddleware} from 'redux';
//支持异步操作action
import thunk from 'redux-thunk';
//2.引入汇总后的ruducer
import reducer from './ruducer/index';
//3.创建store并暴露
//applyMiddleware(thunk)异步操作时使用,没有异步省略
export default createStore(reducer,applyMiddleware(thunk))
创建reducer:
//reducer/index.js
//引入combineReducers来合并reducer
import {combineReducers} from 'redux';
import count from './count';
import user from './user';
//合并reducer,并暴露,combineReducers传入一个对象key:value的形式,
export default combineReducers({
//自定义名称:reducer模块,因为名称一样,基于es6省略,下同
count,
user
})
首先实现count组件的功能,user组件同理:
//reducer/count.js
//使用 * as引入常量
import * as at from '../constant';
//自定义默认值
const initState = {
num:18
}
//定义reducer
let count = (state=initState,action)=>{
switch (action.type) {
case at.INCRE:
return {...state,num:state.num + action.num}
case at.DECRE:
return {...state,num:state.num - action.num}
default:
return state;
}
}
export default count
创建常量文件:
//countant.js
//暴露使用到的常量,通常一个文件
export const INCRE = 'incre'
export const DECRE = 'decre'
export const INCREASYNC = 'increAsync'
创建count的action动作文件:
//action/count.js
import * as at from '../constant';
//分离action动作,并暴露
export const increAction = (val)=>{
return { type: at.INCRE, num: val * 1 }
}
export const decreAction = ()=>{
return { type: at.DECRE, num: 1 }
}
//异步操作时在action里操作,返回一个回调函数,同时传递dispatch,
//异步操作也是调用同步操作方法,直接在action里调用,不经过组件自身
export const increAsyncAction = (val,time)=>{
return (dispatch)=>{
setTimeout(() => {
dispatch(increAction(val))
}, time);
}
}
读取操作数据:
//components/count.js
import React, { Component } from 'react'
import store from '../store';
import {
increAction,
decreAction,
increAsyncAction,
} from '../store/action/count';
export default class count extends Component {
input = React.createRef();
incre = (val) => {
store.dispatch(increAction(val));
};
decre = () => {
store.dispatch(decreAction());
};
increAsync =(val,time)=>{
store.dispatch(increAsyncAction(val,time));
}
render() {
return (
<div>
{store.getState().count.num}
<button onClick={()=>{this.incre("1")}}>+1</button>
<button onClick={this.decre}>-1</button>
<input type="text" ref={this.input} />
<button onClick={()=>{this.incre(this.input.current.value)}}>点击加数值</button>
<button onClick={()=>{this.increAsync("1","500")}}>异步加</button>
</div>
);
}
}
通过subscribe监听数据变化:
//index.js最后加入这么一句
store.subscribe(()=>{
ReactDOM.render(<App />, document.getElementById("root"))
})
这样count组件的功能就可以实现了。
三、react-redux版
在redux的基础上实现redux数据与ui组件的分离.
首先使用Provider包裹App根组件,传递store,使得所有组件都能使用store。
import { Provider } from 'react-redux'
ReactDOM.render(
//Provider为所有组件提供store
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
)
在组件里引用react-redux里的connect方法,connect接收两个参数mapStateToProps,mapDispatchToProps对象,将组件在最后暴露:
//mapStateToProps:映射状态,返回值是一个对象
//-mapDispatchToProps:映射操作状态的方法,返回值是一个对象
export default connect(
(state) => ({
count:state.count,
user:state.user
}),
// dispatch =>({
// incre:(val)=>dispatch(increAction(val)),
// decre:()=>dispatch(decreAction()),
// increAsync:(val,time)=>dispatch(increAsyncAction(val,time))
// })
//mapDispatchToProps对象的简写
{
incre: increAction,
decre: decreAction,
increAsync: increAsyncAction,
}
)(count);
在组件中读取数据时:
<h2>这是Count组件:下方的组件列表长度为:{this.props.user.length}</h2>
{this.props.count.num}
在组件中操作状态的方法:
incre = (val) => {
// store.dispatch(increAction(val));
this.props.incre(val)
};
decre = () => {
// store.dispatch(decreAction());
this.props.decre()
};
increAsync =(val,time)=>{
// store.dispatch(increAsyncAction(val,time));
this.props.increAsync(val,time)
}
这样就完成了对count组件的react-redux化,user组件相同
四、两个组件之间数据共享
- 1.使用combinReducers合并对象,定义好模块名与模块对应 ;
//引入combineReducers来合并reducer
import {combineReducers} from 'redux';
import count from './count';
import user from './user';
//合并reducer,并暴露,combineReducers传入一个对象key:value的形式,
export default combineReducers({
//自定义名称:reducer模块,因为名称一样,基于es6省略,下同
count,
user
})
- 2.在组件里mapStateToProps取值,如user组件取count的组件:
export default connect(
state=>({
user:state.user,
count:state.count
}),
{
addUser
}
)(user)
在页面上读取:
<h2>这是User组件:上方组件总数为:{this.props.count.num}</h2>
五、可优化的地方
- 1.使用react-redux后无需监听数据变化来进行渲染,connect方法会自动进行 页面渲染;
- 2.mapDispatchToprops参数对象会自动进行dispatch分发动作,因此它也可以是一个对象,可以简写成{incre: increAction,…},可以设置名称相同,那么只需写一个incre即可。
- 3.箭头函数一个参数可以省略括号,return 是一个对象时可以省略return关键字,同时使用一个小括号包裹。
六、完整代码
https://gitee.com/maya1024/react-exercise
注:src里的是react-redux版,需要运行redux版时,将使用redux文件夹修改为src,原src另外修改个名字即可