react、redux的设计理念梳理

针对reactreduxmobx-react的概念梳理

主题:

本次培训主要侧重于思想,具体的实现方式各自参照官网,都有详尽的描述
设计思想上的理解可能相对更需要讲解一下,所以本次培训与之前的vue不同,侧重于概念引导

目标:

  • 理解spa设计理念
  • 理解react设计理念
  • 理解redux设计理念
  • 理解mobx设计理念

目标人群:

  • 有一定的MVVM知识基础
  • 上手过MVVM的项目,理解各种情况的下的通信方式

技术文档:

1. SPA(Single Page APP)

介绍react之前,先要介绍一下SPA。

  • 什么是SPA?

    顾名思义,单页应用。
    概念上区别于传统的jsp,页面的刷新根据服务器的响应内容构造,本质上是不同的html文件的交替展示。
    单页应用的渲染只会在一个html中不断更新DOM树。

  • 为什么使用SPA?
    1. 前后端分离的最优解。

      RESTFUL API和AJAX为桥梁,将前后端的关注点彻底剥离开
      后端工程师不需要再操心数据如何嵌套入页面,专心投入到业务逻辑中去。
      前段工程师不需要再操心数据要如何取得以及保存,专心投入到用户交互中去。
      技术栈的剥离也轻松完成
      2. 服务器压力减小。
      > 服务器不需要再操心页面的构建,返回内容中不会再有大量的html文本,极大增加吞吐能力。
      3. 提高可复用率。
      > 不再需要像过往一样,为PC,手机,平板单独进行开发,一套API甚至一套前段代码可以胜任各种场景。

2. JSX

  1. 关注点分离:

    区别于angular的htmlcssts的语法分离解耦方式
    jsx以组件为单位,将构成组件所关注的内容揉在一个jsx文件内。
    此举有利有弊
    利在于可以更直观方便得清楚此组件的工作方式
    弊在于大量代码存在时结构不太分明

    helloWorld.jsx:

      // 常量定义(ts)
      const name = 'Josh Perez';
    
      // render函数内定义标签内容(html)
      public render(): JSX.Element {
        return (
          <h1>Hello, {name}</h1>;
        );
      }
    

3. REACT:

  1. 组件

    • 页面的最小组成单位,可以将其理解为一块积木。

      一个完整的页面是由无数个积木组成,而根据需求可以将积木随意搭配组合,进而构建出不同的页面。
      + 低耦合的可复用化单位
      > 在SPA应用编程中,组件化的概念必须深入人心,这样才能做出结构清晰,逻辑干净的工程

  2. props

    组件接收参数的单位。概念等同于angular的@Input

      // Clock组件
      class Clock extends React.Component {
        render() {
          return (
            <div>
              <h1>Hello, world!</h1>
              <h2>It is {this.props.date}.</h2>
            </div>
          );
        }
      }
    
      // App组件
      class App extends React.Component {
        render() {
          return (
            <Clock
              date="2019-01-01"
            />
          );
        }
      }
    
  3. state:

    区别于props,state是组件的私有状态,不与父组件产生交互

  4. 渲染表达式:

    react的风格与angular、vue不同,渲染标签的逻辑更像传统的jsp。

      class Clock extends React.Component {
        render() {
          return (
            <div>
              <h1>Hello, world!</h1>
              // 类比*ngIf
              if (this.props.showDate) {
                <h2>It is {this.props.date}.</h2>
              }
    
              <ul>
                // 类比*ngFor
                {props.list.map((post) =>
                  <li key={post.id}>
                    {post.title}
                  </li>
                )}
              </ul>
            </div>
          );
        }
      }
    
  5. 关于状态提升以及单向数据流:

    • 在react的世界里,数据是自上而下流动的,即单向数据流

      1. 设计理念

        这里先来看一下react组件的构造思想,每一个组件可以认为是一个函数,由更大的函数对其进行调用,传参,操作其返回值
        还是这个例子

          // Clock组件 将其理解为函数定义 function clock(date)
          class Clock extends React.Component {
            render() {
              return (
                <div>
                  <h1>Hello, world!</h1>
                  <h2>It is {this.props.date}.</h2>
                </div>
              );
            }
          }
        
          // App组件
          class App extends React.Component {
            render() {
              return (
                // 此处理解为函数调用 clock(date),返回值为一个div
                <Clock
                  date="2019-01-01"
                />
              );
            }
          }
        

        为什么要讲函数设计呢?
        纯函数与非纯函数的区别,就是非纯函数可能会产生副作用,即对传入的参数进行了修改。
        而react的设计理念中,一个组件就是一个纯函数,他接收参数,但不会对其进行修改。

          // 纯函数
          // 对于相同的参数总是返回相同的结果
          function getSquare(x) {
            return x * x;
          }
        
          // 非纯函数
          function getSquare(items) {
            var len = items.length;
            for (var i = 0; i &lt; len; i++) {
              items[i] = items[i] * items[i];
            }
            return items;
          }
        
      2. 实现方式

        假如需求变为一个组件可以显示时间,并且可以修改
        此处相当于将angular的双向绑定语法糖拆散

          // App组件
          class App extends React.Component {
            handleChange(e) {
              this.setState({date: e.target.value});
            }
        
            render() {
              return (
                <Clock
                  date="2019-01-01"
                  // 将数据及数据变化后应该做什么告知子组件
                  onDateChange={this.handleChange}
                />
                <Time 
                  date={this.state.date}>
              );
            }
          }
        
          class Clock extends React.Component {
            // 外部数据变化时,调用外部指示的方法
            handleChange(e) {
              this.props.onDateChange(e.target.value);
            }
        
            render() {
              return (
                <div>
                  <h1>Hello, world!</h1>
                  <input value={this.props.date} onChange={this.handleChange} />
                </div>
              );
            }
          }
        
      3. 设计优势

        • 所有状态的变化可追溯

        父组件维护了一个状态,假设子组件可随意更改父组件甚至祖宗组件的状态
        那各组件的状态改变就会变得难以追溯,父组件的状态也可能被子组件意外修改而不可察觉。
        而单向数据流的设计会严格掌控状态的变化,所有的状态变化都是由编码者所控制的。
        这样的程序在工程壮大后可维护性会显著增强

        实现方式很多,比如:

        1. 调用父组件传进来的方法
        2. 在子组件中dispatch一个action来对全局状态修改
        3. 全局状态在通过props分发给子组件
        4. 子组件推送一个事件,订阅方捕获变化
    • 状态提升

      当APP组件中存在以下两个组件:
      【1】可以修改并展示时间的组件
      【2】【1】修改后的时间format处理后展示
      这时【1】组件的状态变化后,【2】组件必须也能捕捉到,进而进行format展示
      所以状态需要保存在APP组件内,由APP控制业务流的流转。
      详细介绍可以参照官网:状态提升

  6. 关于双向绑定:

    angular的双向绑定本质是value + onChange的语法糖。
    react没有这样的语法糖,严格将状态变化的控制交到程序员手中
    参照5-2(单向数据流-实现方式)

  7. 进阶:

    设计理念理解之后,就可以参照官网进行进阶学习了。
    react官方文档

4.REDUX

  1. 先上一个思考题,有如下APP:

    E需要实时渲染D中变化的值

      // A
      <div>
        <B/>
        <E/>
      </div>
    
      // B
      <C/>
    
      // C
      <D/>
    
      // D
      <input value="name"/>
    
      // E
      <p>name</p>
    

    根据单向数据流以及状态提升的规则,需要在A组件中定义“name”,以及“onNameChange”回调
    然后一路传给B、C、D。
    D中发生变化时,再将状态变化事件一路回传给A
    A接收到变化后,再将变化后的值交给E去渲染。

    很显然,这个数据流的传递又臭又长,可能会让你怀疑自己的工作是不是太弱智了些
    于是,REDUX诞生了

  2. REDUX干了些什么?

    redux创造了APP的单一数据源概念,以依赖注入概念的实现方式,将组件的耦合性彻底打散
    redux相对于react来说,可以理解为全局状态,独立于组件树之外。
    使用方式参照官网REDUX

    • redux的解决方案

      假设在redux中定义一个变量name,D需要表示并修改name
      所以redux将name作为prop传递给D,将onNameChange作为action分发给D
      当name发生变化时,D来触发action,告知redux更新name

      E需要表示name,所以redux将name作为prop传递给E,当全局状态发生变化时,自动更新传递给E的name

    • redux的优势

      经过redux的洗礼,与name状态无关的A、B、C组件完全没有意识到name的存在
      他们可以更为专注得去完成自己的任务,而不用操心其他的数据传递任务
      从敲出来的代码,到设计上的思想,都彻底得完成了去耦

    • redux的劣势

      redux的设计为纯函数式,每一个小状态的变化会重新返回一个新的,完整的全局状态。
      当状态无比庞大时,一次更新的消耗是巨大且负担不起的
      所以当你的工程会有庞大数据量的时候,选择redux请三思
      那么当数据量无比庞大时,就没有办法了吗?

5.MOBX-REACT

  1. mobx的解决方案

    当数据量很大时,redux的全局状态深度拷贝工作变得非常臃肿,内存及CPU资源会被压榨得喘不过气
    于是mobx做出了面向对象的设计,将状态的变化锁定至对象中的某个属性,
    一次变化只会针对全局状态中的某个小属性进行修正,资源问题得以解决。
    具体使用方式,参照官网mobx-react

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容