react-redux
Posted 1998a-mei
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了react-redux相关的知识,希望对你有一定的参考价值。
react-redux
我认为我的学习能力应该是挺笨的,哈哈哈哈,小学应该就是我能力的巅峰了。刚开始接触react的时候,因为原生的能力就一般,好在自己能够坚持下来,虽然现在react不能轻车熟路,但是也有了一个最基本的把握,今天就来讲讲react-redux的用法吧。
首先,我先说明一下redux是什么,他是个啥玩意?
先来看看React里面的数据是怎样传递的()
1. 可以看到,一般都是团长等高级干部商量好对策之后(this.state设置好)
2. 把命令一层层的传递下去执行(this.props渲染)
3. 要是哪里发生了什么新的敌情了(想更新页面内容了)
4 .就得一层层往上报告(通过回调一层层把数据传上去),此过程也必须一层层往上传递,不能越级,下面有解释
5. 团长做出决断后再发布命令传下去执行(通过setState修改数据并重新渲染)
这很容易看出这个过程是不能越级的,只能一级一级的来,就像图中一连长发现敌情不能直接报告团长,而必须先报告给一营长,一营长再报告给团长,这个过程多耗时间啊,等连长知道了都得让人一锅端了.......,所以有什么办法能够直接告诉连长呢?这个时候redux兄台就出来说道说道了。
Redux横空出世
所以说层级不深,组价之间也没有什么公用数据的时候,用React自身的setState其实也可以了,可是嵌套一深,或者组件有一些公用数据时就比较麻烦了,于是就有了redux(其实之前还有个flux),回到这个例子就是,他们在整个团之外又建立了一个通讯班(Redux):
分清两个state
在说Redux之前,我想说一下自己学的时候遇到的一个小坑,就是Redux中的state和React中的state完全不是一回事,React中的state是组件内部自己的状态信息,而Redux中的state是Redux自己的数据,然后React就拿Redux中的数据来用,其实Redux也可以在其他框架下使用,并不是非要跟React一起使用。
简单画个图看起来就像下面这样:
接下来我们就来深入了解了redux啦~
store
store:首先要创建一个对象store,他有三个方法。store.getState()用来获取外界Redux的数据,store.dispatch()用来修改外界Redux中的数据,store.subScribe()用来监听store中的数据变化。
import { createStore } from 'redux';
const store = createStore(reducer);
action
action:描述我要干啥,一般是一个对象的形式,其中有一个type字段是必须要有的,比如:{ type:‘请求增援’ },还可以带点数据{ type:‘请求增援’,gun:"100" }
reducer
reducer:撸开袖子真刀实枪的就去干了,比如一连长要求增援,增援要求是100杆枪,团长马上就给你加了100杆枪送了过去。
const defaultState = 0;
const reducer = (state = defaultState, action) => {
switch (action.type) {
case '请求增援':
return state + action.gun;
default:
return state;
}
};
action和reducer也可以想象成产品经理和程序员的关系。
- 产品经理:“我要一个按钮,圆角的”
- 程序员:“嗯,做好了”
- 产品经理:“换个颜色吧,红色”
- 程序员:“ok,换好了”
差不多就是这样,产品经理并不操心具体怎么实现的,他只说他想要干什么(type),然后再提点实现的要求(各种其他的数据),程序员就去具体实现(reducer,修改state,然后返回一个全新的state,这里注意我们并没有直接返回原来的state,我们返回的是一个全新的state对象,因为reducer函数是一个没有副作用的纯函数)
那怎么去触发这个操作(action)呢,就好比说我一连长发现敌情了,我怎么报告给通讯班,让通讯班来处理呢?
就是上面提到过的store.dispatch,不过还要加一个参数,那就是action
store.dispatch({ type:‘请求增援’,gun:"100" })
这样就可以触发action,执行reducer,得到一个全新的state。
Redux 和 React
到此为止,Redux自己就折腾完了,那么Redux自己的数据并没有用,它要把数据交给React用才行,接下来讲一讲怎么把数据交给React来用。
上面我们创建了一个对象store,我们要把这个store对象作为props传给React,那React就可以用了。
这个store只能有一个,也就只能创建一次,也就是说你必须在最顶层处创建一个store对象,然后再一层层的传递下去,才能让所有的组件都能获得这个store对象,调用它的方法。
获取Redux中的数据
比如说我要在render函数中显示Redux的数据,那么我就可以先获取它的数据:
store.getState()
然后把这个数据当做props渲染到组件中去就行了。
更新Redux中的数据
如果你要修改它的数据,那就在JSX中调用
store.dispatch( { type:‘请求增援’,gun:"100" } )
响应Redux中的变化
那么这里问题又来了,你调用了store.dispatch之后Redux中的数据确实改变了,可是React并没有什么变化啊。也就是说React中的render函数并没有被触发呀是不是,就好像React中你直接修改React中的state是没有用的而必须调用React的setState才能重新渲染。
因此,为了让Redux的数据一改变我们就重新渲染,Redux自己提供了一个方法叫做
store.subscribe(render)
这个函数可以监听Redux中state的变化,一旦Redux中的state发生了变化,render函数就会被调用,页面就会被重新渲染。
上面这个过程就是手动调用的过程,但这样调用有点麻烦,因为要让所有的子组件都能应用store中的数据,那么所有的组件就都要把store当做props传进来,这也太麻烦了。
还是那之前那个例子来说,你一连长发现了敌情,是不用层层上报了,可以直接报告给通讯班,通讯班再生成新的命令,可问题是,你从下往上打报告是简单了,可是从上往下发布命令仍然是一层层的传递的呀。
就好比说,一连长发现了敌情,报告上去,通讯班做出决定让三连长带人去打,通讯班还是得通过团长--营长--连长这条路去一层层发布命令,能不能让通讯班直接就通知三连长呢,当然是有的,这就是我们的React-redux库
React-redux
这个是需要你自己去用npm额外安装的。
使用这个方法之后,我们就不需要一层层往下发布命令了
在React-redux中有两个比较关键的概念:Provider和connect方法。
一般我们都将顶层组件包裹在Provider组件之中,这样的话,所有组件就都可以在react-redux的控制之下了,但是store必须作为参数放到Provider组件中去
<Provider store = {store}>
<团长/>
<Provider>
这个组件的目的是让所有组件都能够访问到Redux中的数据。
这个比较简单,我们主要讲connect方法。
connect方法:
connect(mapStateToProps, mapDispatchToProps)(MyComponent)
其实connect方法一共有4个参数,这里主要讲前两个。
mapStateToProps(mapState)
字面含义是把state映射到props中去,意思就是把Redux中的数据映射到React中的props中去。
也就是说你React想把Redux中的哪些数据拿过来用。
比如这里二连这个组件想要渲染自己枪支的数量。就可以直接在二连这个组件中把Redux中的gunOfErlian拿过来用
const mapStateToProps = (state) => {
return {
gun: state.gunOfErlian
}
}
然后渲染的时候就可以直接使用this.props.gun
class Erlian extends Component {
constructor(props){
super(props);
}
render(){
return(
<div>{this.props.gun}</div>
)
}
}
Erlian = connect()(Erlian);
export default Erlian;
那么这样就可以实现渲染,就是把Redux中的state变成React中的props。
mapDispatchToProps(mapDispatch)
通过上面的分析,相信这个函数也很好理解,就是把各种dispatch也变成了props让你可以直接使用
然后就到了我们这里最重要的一点了。
他有两种用法:
方法1:
const mapDispatch = (dispatch) => {
return {
onClick: () => {
dispatch({
type: '请求增援',
gun : 100
});
}
};
}
export default connect(mapDispatch)(One)
方法2:
import { bindActionCreators } from 'redux'
.......
const mapDispatch = (dispatch) => {
bindActionCreators(actionCreator.dispatch)
}
//但是这个方法与下面的方法是等价
export default connect(mapDispatch)(One)
但是方法2极力不推荐!!!
更改一下上面的One组件
class Erlian extends Component {
constructor(props){
super(props);
}
render(){
return(
<div>{this.props.gun}</div>
<button onClick = {this.props.onClick}>请求增援</button>
)
}
}
Erlian = connect()(One);
export default One;
当我点击请求增援按钮后,Erlian组件的枪支数量会自动的更新,而不需要我们手动的去用store.subscribe订阅render函数以达到更新页面的目的。
这样一来我们就不需要一层层的传递store对象了。
这种随处都可以使用、修改Redux中的数据的方式确实很方便,但Redux推荐的最佳实践还是在尽可能少的地方使用connect,把逻辑,数据相关的都放到容器组件中去处理,其他的组件都由容器组件所生成的props一层层传递下去然后渲染(傻瓜组件),这里就不多说了。
这一次的小结差不多就这样了,许多代码细节部分都没有写,更多的是对他们的作用的理解,因为自己在学习的时候,更多的是一些理解方面的困惑,而更多更全面的代码部分在Redux官方文档或是阮一峰老师的博客中都已经写得非常清楚,大家可以去看看,理解了上面许许多多的名词以及他们的含义之后,相信那些文档会更容易看懂。
上述若有错漏之处,烦请各位在评论区指出。
以上是关于react-redux的主要内容,如果未能解决你的问题,请参考以下文章