React-Redux基础(二):React 里面如何使用 Redux,Redux 修改操作

上篇博客,我们说了原生 redux 的用法,这一篇我们就来说说如何和 react 来配合,因为 redux 这个东西尽管能单用,但是很少这么做。

首先第一件事,安装:npm install redux react-redux -D

redux 是这个东西的本体,核心,没有它就用不了。

react-redux 它则是一个桥梁,它让我们的 react 可以使用 redux。

在用之前,我们需要先认识三个主要的组件:

1,Provider,翻译过来是提供者。它是一个包裹,它负责包裹住我们的整个程序

因为我们的 redux 是希望能够在整个程序之内来共享数据的,所以你就得把整个程序全都交给它来处理,那么它就需要在所有的程序之外。它有点像我们前面说过的 Router,Router 它也是包在最外面的。

2,connect,因为实际上来说,它是在最外面没错,你整个程序都在它里面,都归他管。但是如果你自己一级一级往上找,去找到它,然后在去拿数据,这个也是及其费劲的。所以这个 connect 它是起到一个连接的作用。

那这个连接是干什么的呢?它可以帮助我们的模块来访问 redux。

3,reducer,我们在这篇博客里面,会看到 reducer 怎么样能够跟我们的组件配合起来。

首先,我们将上节课原生的代码删了,因为我们不会在单用 redux 了。将代码恢复到之前的状态:

接下来第一件事就来了,我们需要把整个程序给包住。那么最简单的方法莫过于放到 index.js 里面,因为 App 就在这里。

首先,我们需要先引几个东西:

我们需要先把 createStore 给引进来,因为 redux 必须得创建一个 store,才能开始用。

注意,createStore 它是 redux 所提供的功能。而 Provider 和 connect,它们不是 redux 的功能,是 react-redux 的功能。

所以我们在引入的时候,注意不要将 redux 和 react-redux 里面的东西搞混了。

简单来说下是为什么:因为 redux,它只提供存储。它自己什么也没有,上一篇博客我们也见识过了。

react-redux 它是一个桥梁,它帮助我们来跟 redux 做整合,所以 Provider 和 connect 都是它来提供的,因为是它来帮助我们的组件来访问 redux 的。

接下来,先不忙着包裹,我们先创建一个 store:

到目前为止,和以前 redux 单用的写法是没区别的。那么接下来怎么去把它包起来呢?

这个 Provider 它在最外层,把我们整个程序全都包住。这里稍微提下,Provider 和 Router 是会有冲突的,这个后面会细讲,这里大家先有个印象。

为什么这里要给它传一个 store 对象的参数呢?

因为说白了,你在这光是 create 一个 store 是没有办法起作用的,别人不会自动去找这个程序里面,所有带 store 的变量在哪,得你主动把 store 给 Provider 传过去,意思就是告诉它,这个程序所有的数据都归它管。

那么准备工作做好了,那在组件里面怎么用呢?

首先,我们第一件事是需要先把这个组件,给它 connect 连接到整个 redux 上面去。

怎么做呢?第一步,我们先引入 connect:

这里注意别引错了,它在 react-redux 里面,而不是 redux 上。

然后有 connect 之后,它怎么用呢?它的用法略微有点奇怪,不是放在 class 里面,而是放在外面的。

我们在 export default 的时候,需要用 connect 来把 App 给包裹住

这里是执行两次,所以会有 2 对小括号。

执行第一次的时候,它里面有一些参数。然后执行第二次的时候,才是我们具体要包裹的元素。

那么第一次执行的参数又有什么呢?

它的参数有 2 个第 1 个是个函数,第 2 个是个 json: 

函数我们又可以写成箭头函数,所以如下图:

这里简单来解释下 connect 它这 2 个参数都有什么用处。

首先第一个函数,它是专门用来合并东西的。合并什么呢?

我们要明白,所有来自 redux 的数据,不会直接成为你的 state,你的 state 还是你的 state。(这里说的 state 是组件内的 this.state)

实际上在 redux 官方里面,它是推荐你:如果一些数据只是在我这个组件之内用,那你就不要往 redux 身上扔。

因为 redux 里面越干净,越少越好。所以你的 state 还是你的 state,我们不碰它。(这里说的 state 是组件内的 this.state)

那这个时候,它带过来的数据放哪呢?它是放在你的 props 身上。换句话说,它给你加了个 props。

所以,这个函数具体来说,它会给你 2 个东西。

第一,它会给你一个 state,这个 state 是它的 state,也就是我们传到 reducer 里面的那个初始数据

然后接下来,这个 props 是你的,就是你在组件内使用的 this.props

所以,这个函数内的第一个参数 state,是来自于 redux 里面的全局数据 state。

而第二个参数 props,来自于我们自身的 this.props,就是将来谁去用你这个组件,它传给你的参数。

而我们要做的就是把它们两个合并起来。因为它们可能会冲突,毕竟它们都是体现在 this.props 身上的。

为什么要把它们两个要合并呢?

比如现在 state 里面有个 name,然后 App 组件上面,它自己也有个 name:

如果不冲突一切都好办,那这时候就出现问题了,就冲突了:全局数据的 state 里面有 name,组件自身也有 name。

那我应该听谁的?还是说改个名什么的?我们可以先把它们打印出来看看:

所以这个时候就需要我们自己来合并了。

然后合并的时候,我们希望以 state 为主,换句话来说,就是我希望更多的来使用 redux 里面的东西。

那么,我们可以使用 Object.assign 这个方法来进行合并:

看到这里,你可能会很奇怪,上面你不是说以 state 为主吗,那为什么这里把 state 放后面?

实际上来说是这样的,因为我把 state 放后面,那 state 里面的东西就会覆盖到 props 里面去。

换句话说,如果同样有 name,那我用的就是 state 里面的 name。因为它是覆盖别人的一方。

接下来,我们这么做是有 2 个小问题的:

第一,我们可以简化。因为它这个函数就只是返回这一个东西,所以可以直接这么写:

第二,直接覆盖是有问题的。其实说白了就一件事,props 不能覆盖。我们在前面的 React 基础里面就说过,props 是只读的

所以我们可以在前面加上一个空对象:

这个意思就是说,先把 props 里面所有的东西,全部复制到这个空 json 里面去。

然后再把 state 里面的东西全覆盖到 json 里面去。

这样的话,万一 state 和 props 有冲突,也是以 state 的为准,因为它是后进去的。

然后这时候,我们希望把名字和年龄给打印出来,怎么做呢?

其实 redux 它里面的数据,也就是 state 里面所有的东西,最终都会进到 props 里面去。

所以我们可以用 this.props.xxx 来找相应的东西:

可以看到,就是这么简单。

对于初学者,这里比较容易混淆。那么,我们再来回忆一下。

首先,我们这个 redux,它里面的数据 state,会自动的进入到我们组件里的 props 里面,而不是我们组件里面的对象 this.state

比如,我们可以把自己的 state 初始化一个 a 属性。然后在 render 里面打印下我的 state,以及我的 props:

可以看到,我们自己的 state 里面,就一个 a: 0。

所以 redux 不会把它里面的数据放到你的 state 里面去,它只会放到你的 props 身上。

因为 props 是不可修改,只读的,并且结合我们前面说过的,redux 它本身就是一个单向的。

它不太希望你直接去给我 redux 的 state 赋值,因为你这样做会破坏我的单向数据传递。所以在这个时候,它就把数据直接放到 props 里面。

其实,这样做,即是方便了我们用,也能够不干扰我们自己组件的局部状态 this.state,同时也能够防止我们对它直接赋值。

所以一举三得,这个就是 redux 最基本的使用。

然后,我们前面说过,redux 是在整个程序之内,去共享数据的。

换句话说,我现在只有一个组件,其实是看不出来 redux 优势的。

那么我们就再来一个组件 Cmp1.js:

然后在 App.js 里面引入:

可以看到数据是没问题的。

那么我们真正想做的是,能够在 Cpm1 组件里面放一个按钮,然后点击的时候,可以给 age 加个3:

那么具体怎么做呢?这时候我们就需要 connect 的第二个参数了。这个参数,是用来封装 action 的。

我们在上一篇博客里面说过,你可以通过 dispatch 来做,但是这样略微有一点麻烦。

所以我们的 react-redux,它可以帮助我们来封装我们的这个 action。

简单来说,我们直接在里面写方法就行。比如,我们就叫 addAge:

addAge 这个名字叫啥都行,因为这个不是全局的,它只是在你这个组件之内来用的,所以你不用担心。

然后我们可以给这个 addAge 传个参数,传什么都行,随便你。因为这是你自己的方法。比如我们传个 n:

然后接下来,我们就可以来调用它:

那么 addAge 它里面具体需要做什么呢?

如果说它里面还要继续写 this.store.dispatch,那我们封装它就没有意义了,还不如我们直接拿到上面的 fn 里面去写,看着也方便。

所以这个 addAge 它里面极度的简化,我们自己不需要去 dispatch,它替我们都封装好了。

所以你只要 return 一个需要提交的 action 对象就行了,其余的工作它替你搞定。(前面我们有说过 action 就是一个 json,所以这里直接 return 一个空对象就行)

所以这里的意思就是:你就告诉我,你的 action 是什么,其他的我来。

然后 action 里面需要 2 个东西:

第一个是 type,这个是必须的,并且两边也必须得一样。

第二个 n,就是对应的参数。

这里和我们上一篇博客里面讲的 action 其实是一样的。

所以 connect 里面的这个操作,它帮助你简化了,你自己不需要去 dispatch,它替你封装好了,你只需要给它返回一个需要提交的 action 对象就好了。

那如果我还想再来一个组件 Cmp2,改姓名:

和上面一样,需要注意的就是 type: 'setname',必须得和 index.js 里面的 reducer 里面的 setname 一致:

然后在 App.js 里面引入:

所以,我们就简单的讲解了:

1,react 里面如何使用 redux。

2,redux 它里面的东西,要如何修改。

那么到此,这个东西就已经完成了。

其实我们现在这个东西还算不上完美,因为它里面还有很多问题:

比如现在,我们在 index.js 里面用的是一个单一的 reducer。

你想象一下,整个项目当中,所有的数据全在这一个函数里面,就问你怕不怕。

因为如果说真的把所有的数据全扔到这一个函数里面,那整个程序的数据太多了,这个函数会写死人的,负责维护这个函数的人辞职率会贼高。

所以我们要想办法怎么样把它做成多套东西,也就是把它拆成模块。比如这个是用户数据,那个是它的购物车数据,等等。

所以我们要考虑的第一个问题就是:如何不要这种单一数据对象,而是多个联合的数据对象,这个会更好一点。

第二个问题就是,在程序里面,但凡是改了某一个东西,就顺便还需要更改别的地方。这种情况,都是不应该发生的。

实际上来说,如果我在将来因为项目规范,又或者觉得名字不好听,等各种原因,把 setname 改成了 set_name:

那么实际上,所有用到你这个 setname 的地方,就都得改。

如果项目小,想一下还能记起来哪些地方要改。但是对于一个大型的项目来说,靠记忆,你觉得靠谱吗?如果负责这个模块的同事离职了,下一位接盘的估计得哭死。

所以说,我们还有另一个问题,就是这个 action,它是一个字符串。那怎么样才能把它提取出来,让它是一个比较容易修改的状态,这就是我们需要解决的问题。

发布了78 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43921436/article/details/105432492