# 一、react 简介

  • 专注视图层,可以与其他框架搭配,构建大型应用.
  • 虚拟 dom,性能(dom 操作性能消耗最大)。真实页面对应一个 DOM 树。
    • 传统:传统页面的开发模式中,每次需要更新页面时,都要手动操作 DOM 来进行更新
    • 每次数据更新后,重新计算 Virtual DOM,并和上一次生成的 Virtual DOM 做对比,对发生变化的部分做批量更新。React 也提供了直观的 shouldComponentUpdate 生命周期回调,来减少数 据变化后不必要的 Virtual DOM 对比过程,以保证性能
  • 函数式编程(react 的精髓)
  • jsx 语法

# 二、函数式编程

# 对比

  • 命令式编程:命令式编程解决的是做什么的问题,执行命令,命令式编程关心解决问题的步骤
  • 函数式编程:是一种”编程范式”(programming paradigm),主要思想是把运算过程尽量写成一系列嵌套的函数调用,函数式编程关心数据的映射

# 特点

  • 函数是”第一等公民”,指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值
  • 只用”表达式”,不用”语句”

    TIP

    “表达式”(expression)是一个单纯的运算过程,总是有返回值;”语句”(statement)是执行某种操作,没有返回值。函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。

  • 没有”副作用”

    TIP

    函数式编程强调没有”副作用”,意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值。

  • 不修改状态

    TIP

    函数式编程只是返回新的值,不修改系统变量。

  • 引用透明

    TIP

    引用透明(Referential transparency),指的是函数的运行不依赖于外部变量或”状态”,只依赖于输入的参数,任何时候只要参数相同,引用函数所得到的返回值总是相同的。

# 意义

  • 代码简洁,开发快速

    TIP

    函数式编程大量使用函数,减少了代码的重复,因此程序比较短,开发速度较快。

  • 接近自然语言,易于理解(demo)
  • 更方便的代码管理

    TIP

    函数式编程不依赖、也不会改变外界的状态,只要给定输入参数,返回的结果必定相同。因此,每一个函数都可以被看做独立单元,很有利于进行单元测试(unit testing)和除错(debugging),以及模块化组合。

  • 易于”并发编程”

# 三、 jsx 语法

# 1. jsx 的由来

  • 描述

    虚拟元素可以理解为真实元素的对应,它的构建与更新都是在内存中完成的,并不会真正渲染到 DOM 中去。在 React 中创建的虚拟元素可以分为两类,DOM 元素(DOM element)
    与组件元素(component element),分别对应着原生 DOM 元素与自定义元素,而 JSX 与创建元素的过程有着莫大的关联
    
  • dom 元素的,react 的创建元素类似

    <button class="btn btn-blue">
      <em>Confirm</em>
    </button>
    {
      type: 'button',
      props: {
      className: 'btn btn-blue',
      children: [{
      type: 'em',
      props: {
        children: 'Confirm'
        }
      }]
      }
    }
    ps: 在 React 中,到处都是可以复用的元素,这些元素并不是真实的实例,它只是让 React 告诉
    开发者想要在屏幕上显示什么。我们无法通过方法去调用这些元素,它们只是不可变的描述对象
    
  • 组件元素,react 的创建元素类似

  const Button = ({ color, text }) => {
  return {
    type: 'button',
    props: {
    className: `btn btn-${color}`,
      children: {
        type: 'em',
        props: {
        children: text,
        },
      },
    },
    };
  }
  //创建组件元素的 json 格式
  {
    type: Button,
    props: {
    color: 'blue',
    children: 'Confirm'
    }
  }

# 2. jsx 的基本语法

  • 基本语法

    • 定义标签时,只允许被一个标签包裹;
    • 标签一定要闭合
  • 元素类型

    • dom 元素: 标签首字母为小写字母
    • 组件元素:标签首字母对应大写首字母
  • 注释

    • {/ 节点注释 /}
    • 条件注释:
    <!--[if IE]>
    <p>Work in IE browser</p>
    <![endif]-->
    
    {
    (!!window.ActiveXObject || 'ActiveXObject' in window) ?
    
    <p>Work in IE browser</p> : ''
    }
    
  • 元素属性

    • class 属性改为 className;
    • for 属性改为 htmlFor;
    • 在写自定义属性的时候,都由标准写法改为小驼峰写法
  • Boolean 属性 省略 Boolean 属性值会导致 JSX 认为 bool 值设为了 true。要传 false 时,必须使用属性表达式

<Checkbox checked={true} />
<Checkbox checked />
<Checkbox checked={false} />
  • 展开属性 可以使用 ES6 rest/spread 特性来提高效率

    const data = { name: 'foo', value: 'bar' };
    const component = <Component name={data.name} value={data.value} />;
    
    可以写成:
    const data = { name: 'foo', value: 'bar' };
    const component = <Component {...data} />;
    

# 3. JavaScript 属性表达式

const person = <Person name={window.isLoggedIn ? window.name : ''} />;

# 4.html 转义

React 会将所有要显示到 DOM 的字符串转义,防止 XSS。

  • 直接使用 UTF-8 字符
  • 使用对应字符的 Unicode 编码查询编码;
  • 使用数组组装 {[‘cc ‘, ©, ‘ 2015’]}
  • 直接插入原始的 HTML
  • React 提供了 dangerouslySetInnerHTML 属性。它的作用就是避免 React 转义字符,在确定必要的情况下可以使用它:
<div dangerouslySetInnerHTML={{ __html: 'cc &copy; 2015' }} />

# 四、React 组件

# 1. 狭义上的组件,UI 组件。

说明:组件主要围绕在交互动作上的抽象,针对这些交互动作,利用 JavaScript 操作 DOM 结构或 style 样式来控制。一般会有 3 个部分组件:结构、样式和交互行为

  • 其他知识点 Class
  • demo 实例
  • 规范标准组件的信息
    • 基本的封装性。尽管说 JavaScript 没有真正面向对象的方法,但我们还是可以通过实例化的方法来制造对象。
    • 简单的生命周期呈现。最明显的两个方法 constructor 和 destroy,代表了组件的挂载和卸载过程。但除此之外,其他过程(如更新时的生命周期)并没有体现。
    • 明确的数据流动。这里的数据指的是调用组件的参数。一旦确定参数的值,就会解析传进来的参数,根据参数的不同作出不同的响应,从而得到渲染结果。
  • mvc 架构的演变,模板引擎的加入,可以解决 view 层
  • 弊端:通过改变 class 控制 style 来显示或隐藏。这样的逻辑一旦复杂,就存在大量的 DOM 操作, 开发及维护成本相当高。

# 2. 广义上的组件,带有业务含义和数据的 UI 组件组合

这类组件不仅有交互动作,更重要的是有数据与界面之间的交互。

  • Web Components
  • react 组件: React 组件基本上由 3 个部分组成——属性(props)、状态(state)以及生命周期方法 说明:React 组件可以接收参数,也可能有自身状态。一旦接收到的参数或自身状态有所改变,React 组件就会执行相应的生命周期方法,最后渲染。整个过程完全符合传统组件所定义的组件职责。
  • 对比
    • React 自定义元素是库自己构建的,与 Web Components 规范并不通用;
    • React 渲染过程包含了模板的概念,即 1.2 节所讲的 JSX;
    • React 组件的实现均在方法与类中,因此可以做到相互隔离,但不包括样式;
    • React 引用方式遵循 ES6 module 标准。

# 3. react 组件创建

  • React.createClass
const Button = React.createClass({
  getDefaultProps() {
    return {
      color: 'blue',
      text: 'Confirm',
    };
  },

  render() {
    const { color, text } = this.props;

    return (
      <button className={`btn btn-${color}`}>
        <em>{text}</em>
      </button>
    );
  },
});
  • ES6 classes
import React, { Component } from 'react';

class Button extends Component {
  constructor(props) {
    super(props);
  }

  static defaultProps = {
    color: 'blue',
    text: 'Confirm',
  };

  render() {
    const { color, text } = this.props;

    return (
      <button className={`btn btn-${color}`}>
        <em>{text}</em>
      </button>
    );
  }
}
  • 无状态函数(无状态组件) 它不存在 state,也没有生命周期方法,无状态组件。不像上述两种方法在调用时会创建新实例,它创建时始终保持了一个实例,避免了不必要的检查和内存分配,做到了内部优化。

    function Button({ color = 'blue', text = 'Confirm' }) {
      return (
        <button className={`btn btn-${color}`}>
          <em>{text}</em>
        </button>
      );
    }
    

    # 五. react 数据流

    • 概念 在 React 中,数据是自顶向下单向流动的,即从父组件到子组件。这条原则让组件之间的关系变得简单且可预测。

      state 与 props 是 React 组件中最重要的概念。如果顶层组件初始化 props,那么 React 会向下遍历整棵组件树,重新尝试渲染所有相关的子组件。而 state 只关心每个组件自己内部的状态,这些状态只能在组件内改变。把组件看成一个函数,那么它接受了 props 作为参数,内部由 state 作为函数的内部参数,返回一个 Virtual DOM 的实现。
      
  • state

  • props

# 六. react 生命周期

  • 生命周期
//组件挂载、卸载
import React, { Component, PropTypes } from 'react';

class App extends Component {
  static propTypes = {
    // 挂载过程 执行一次
  };

  static defaultProps = {
    // 挂载过程 执行一次
  };

  constructor(props) {
    // 挂载过程 执行一次
    super(props);

    this.state = {
      // ...
    };
  }

  componentWillMount() {
    // if setState 挂载过程 render 一次
  }
  componentDidMount() {
    // if setState 挂载过程 render 两次
  }
  componentWillUnmount() {
    // 卸载过程执行
    // 我们常常会执行一些清理方法,如事件回收或是清除定时器。
  }
  render() {
    return <div>This is a demo.</div>;
  }
}
  • 数据更新过程 说明:更新过程指的是父组件向下传递 props 或组件自身执行 setState 方法时发生的一系列更新动作。
import React, { Component, PropTypes } from 'react';

class App extends Component {
  componentWillReceiveProps(nextProps) {
    // this.setState({})
  }

  shouldComponentUpdate(nextProps, nextState) {
    // return true;
  }

  componentWillUpdate(nextProps, nextState) {
    // 不能执行 setState
  }

  componentDidUpdate(prevProps, prevState) {
    // ...
  }

  render() {
    return <div>This is a demo.</div>;
  }
}
  • state 更新 如果组件自身的 state 更新了,那么会依次执行 shouldComponentUpdate、componentWillUpdate 、render 和 componentDidUpdate。

  • shouldComponentUpdate shouldComponentUpdate 是一个特别的方法,它接收需要更新的 props 和 state,让开发者增加必要的条件判断,让其在需要时更新,不需要时不更新。因此,当方法返回 false 的时候,组件不再向下执行生命周期方法。

# 七. React 与 DOM

  • ReactDOM

    • findDOMNode 获取 dom
      componentDidUpdate
      componentDidMount() {
      // this 为当前组件的实例
      const dom = ReactDOM.findDOMNode(this);
      }
    
    • refs,组件被调用时会新建一个该组件的实例,而 refs 就会指向这个实例。如果是无状态组件,render 会返回 null。无状态组件挂载时只是方法调用,没有新建实例. refs 同样支持字符串。对于 DOM 操作,不仅可以使用 findDOMNode 获得该组件 DOM,还可以使用 refs 获得组件内部的 DOM。

      componentDidMount() {
      // myComp 是 Comp 的一个实例,因此需要用 findDOMNode 转换为相应的 DOM
      const myComp = this.refs.myComp;
      const dom = findDOMNode(myComp);
      }