react、redux的设计理念梳理

2021-03-30  本文已影响0人  贪得_3440

针对reactreduxmobx-react的概念梳理

主题:

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

目标:

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

目标人群:

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

技术文档:

1. SPA(Single Page APP)

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

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

上一篇 下一篇

猜你喜欢

热点阅读