老博文迁移,原地址

前言

本文将写一个计数器的例子 前备知识: react基本知识 redux的基本概念和api 技术栈: create-react-app redux

1.环境搭建

和vue一样,react也有脚手架: create-react-app
我们将在这上面进行开发
脚手架安装:

  1. npm install -g create-react-app
  2. create-react-app my-app
  3. cd my-app

生成的目录结构:

  1. |----my-app/
  2. |----README.md
  3. |----node_modules/
  4. |----package.json
  5. |----.gitignore
  6. |----public/
  7. |----favicon.ico
  8. |----index.html
  9. |----src/
  10. |----App.css
  11. |----App.js //模板文件
  12. |----App.test.js
  13. |----index.css
  14. |----index.js //挂载点
  15. |----logo.svg

如上我们主要动index.js 和App.js

运行程序:

  1. npm start

作为redux的入门学习例子,我们先不直接霸王硬上弓使用redux,为了熟悉redux的编写思路,我们可以自己撰写方法(function)模拟redux的设计思路。

本节模仿redux涉及的点:

  1. |-- action
  2. |-- state
  3. |-- dispatch
  4. |-- reducer

2.开始计数器demo

接下来我们在App.js写下:

  1. //App.js
  2. import React, {Component} from 'react';
  3. //【3】.根据传来的不同action标识判断应该做出的反应。
  4. //如action的type为INCREMENT时,那么做出的反应就是计算某值,
  5. //并将该值返回做为一个新的state
  6. //reducer
  7. const counter = (state = { value: 0 }, action) => {
  8. switch (action.type) {
  9. case 'INCREMENT':
  10. return { value: state.value + 1 };
  11. case 'DECREMENT':
  12. return { value: state.value - 1 };
  13. default:
  14. return state;
  15. }
  16. }
  17. class MyCounter01 extends Component {
  18. // State 初始化数据state状态
  19. constructor() {
  20. super();
  21. this.state = counter(undefined,{});
  22. }
  23. //【2】.dispatch调用counter函数【即reducer】,
  24. //参数:数据当前的状态state和action动作(该action动作以type字段为标识)
  25. dispatch(action) {
  26. //【4】.以reducer返回的新state更新状态,通过this.setState方法修改状态值
  27. this.setState(prevState => counter(prevState, action));
  28. }
  29. // Actions
  30. increment = () => {
  31. this.dispatch({ type: 'INCREMENT' });
  32. };
  33. decrement = () => {
  34. this.dispatch({ type: 'DECREMENT' });
  35. };
  36. //view层
  37. render() {
  38. return (
  39. <div>
  40. <p>{this.state.value}</p>
  41. //【1】. 用户点击加按钮,触发this.increment函数【即action】
  42. //函数通过 this.dispatch发出action,告诉数据你应该要发生变化啦
  43. <button onClick={this.increment}>+</button>
  44. <button onClick={this.decrement}>-</button>
  45. </div>
  46. )
  47. }
  48. }
  49. export default MyCounter01;

代码中标的1234点就是以下工作流的具体实施过程。
本节中只需要理解
和以往的点击函数实现加减不同,react明显多了两个跳板,一步一步渐进的完成整个动作。

action状态:根据用户的操作事件分发(dispatch)动作(action),每个动作由type标识

reducer:将收到的状态分流,规定某个状态对应数据的怎么变化,并返回一个新数据state

具体根据数据变化更新数据的:this.setState()

02—计数器V0.0 - 图1

总结

在使用redux做做状态管理的组件中,组件内部对应X个参数和X个方法。参数即为数据、状态如这里的this.state.value,方法即为用户的交互或者从外部(父组件传值或网络)获取数据。

当用户点击+按钮触发了一个方法(increment),按照以前的思路,我们会直接在这个组件里定义一个加法,让this.state.value +1. 而现在我们是使用redux做状态管理。

比喻理解开始:
背景:计算鸡王国有个县城今年粮食收成很好,本地仓库与王国仓库中心粮食存量是同步的。现在要改变本地仓库的粮食存量,同时上报计算鸡王国,实时更新王国粮食中心的粮食存量。

思路:小县城发出信号告诉粮食中心我今年收成+1啦,你们快更新仓库粮食总量,粮食中心更新之后,县城便自动更新了本地粮存。

下面我们讨论:

  1. 小县城怎么告诉粮食中心的? 【组件与redux通讯的问题】
  2. 县城怎么自动更新本地粮存的?【组件怎么得到redux的最新数据的】

过程如下:

  1. * 我们的麦子量有两个:本地的state,和reduxstate。本地state绑定自reduxstate
  2. 我们要修改自身的state不能直接修改,即使修改了上面也不承认相当于白修改。就只能通知上面的修
  3. 改,修改了之后我本地实时更新同步。
  4. * 于是我们就发出一个信号(action),这个actiontype就标识了我这个信号的意义。
  5. (相当于古代的信号弹,红色代表巴拉巴拉,绿色代表巴拉巴拉。)。
  6. * 注意:信号的发送也是有讲究的,只能使用皇家钦定的小螺号发送!不然别人信号中转站不认你的信号
  7. this.dispatch({ type: 'DECREMENT' })
  8. dispatch()是 View 发出 Action 的唯一方法
  9. * 然后有个信号中转站Reducer,专门负责接收来自全国各地的信号
  10. reducer负责整合各方旧信息,处理返回新信息。
  11. 它知道现有的+1操作执行之前的(旧的)state值(可以实时通讯了解到仓库里的现有麦子值)与某
  12. 个将要改变仓库状态值的信号弹的颜色(action)。于是它就去它的小本本里翻,看下这个颜色的
  13. 信号弹表示什么意思,哦原来绿色表示要粮仓数要+1.于是它就将旧state+1作为new state返回。
  14. * 然后发出信号的根源地(原组件),收到reducer返回的新state就使用this.setState改变本组件
  15. 的状态。
  16. this.setState(prevState => counter(prevState, action));

以上只是一个模拟实现,目的是理解redux的数据管理思路。

真正的redux是有个store,专门生成一个数据仓库,这里模拟相当于reducer里自带仓库了。
所以也解释了为什么会出现本地state数据..(本地明明可以通过this.setState直接改啊!)

实际中我们如果要将本组件的某个状态值存入redux中(比如页面的主题色),都是通过props直接得到那个值的,不会再去修改它。如果是本组件内部的值,我们也无需将其存在redux中(存入redux的根本目的只是为了便于数据集中管理而已,出于数据复用的情况(个人理解))

所以不要再纠结为什么本地state要绕那么大一圈,费这么多周折去改这个state啦(杀鸡焉用牛刀的疑问)我们只是为了模拟redux数据管理思路而已。。这仅是演习注意注意这只是演习。。
【况且我已经很卖力地套了个生龙活虎的例子让这个模拟看上去不怎么奇怪啦

备注:模拟code例子来自以下链接
从零学习react技术栈 https://yubolun.com/react-learn-3-1/