深入理解React

1,520 阅读3分钟

理解 React 的工作原理

特点:UI是data决定的,高效的Virtual DOM工作机制。

  1. UI = f(D);
  2. 一切皆组件;
  3. Declarative Programming;

UI = f(D)

常见版本控制工具git/svn采用diff算法时间复杂度为O(n^3)。React采用的diff算法时间复杂度为O(n),无法解决节点移位问题(很少遇到)。

  • 动态产生但组建要手动绑定key,key值的引入保证来Virtual DOM的高效工作,但要保证key唯一且稳定。

一切皆组件

希望软件如积木一样,随便拼搭组合。React组件,无状态纯函数

声明式编程(Declarative Programming)vs 命令式编程(Imperative programming)

对比jQuery,声明式只需要关心你想要什么而不必关心具体步骤,这样就避免了版本变动导致API变化但弊端。

JSX 的优势和局限

  • 优点:

历史上,html/css/js的分离处于技术上的原因, 按React的哲学,三者合一比较合理。组件内对全局及局部css的处理最为合理。

  • 缺点:

JSX需要Bable转译,相关webpack配置棘手。

  • 转译示例:
//JSX:
<div>
  {
    arr.maps(x => <div>x</div>)
  }
</div>
//Transpiled JavaScript:
React.createElement(
  "div",
  null,
  arr.maps(x => React.createElement(
    "div",
    null,
    "x"
  ))
);
  • 注意: render里尽可能使用纯函数,避免不纯函数(push,reverse)

props or state

  • props:一个组件外部传入的数据;
  • state:一个组件内部的状态,组件只能通过setState改变其自身state,尽可能将state推到比较边缘的位置。
  • 注意:将父组件props作为子组件state,存在值引用对象的问题

详解 React 组件的生命周期

三种过程:

  1. mount:
    • getDefaultProps
    • getInitialState
    • componentWillMount
    • render
    • componentDidMount(只在浏览器上执行)
  2. update:
  3. unmount:

常见过程:

  • 因state改变引发的update过程:

    • shouldComponentUpdate(节省很多不必要的渲染时间,提高React性能)
    • componentWillUpdate
    • render
    • componentDidUpdate
  • 因父组件想要render这个组件改变引发的update过程

    • componentWillReceiveProps
    • shouldComponentUpdate
    • componentWillUpdate
    • render
    • componentDidUpdate

注意: 以render为界,之前的state/props都是没有被改变的,之后的都被改变;React V16有做优化。

如果shouldComponentUpdate返回false,则render不会执行。子组件可能通过connect连接redux,则会有自己但更新过程,但与此无关。

为什么尽量构建无状态组件

毫无疑问,毋庸置疑

用组件封装副作用但功能:

import React from 'react';

export default class HeartBeat extends React.Component {
  render() {
    return null;
  }

  componentDidMount() {
    this.timer = setInterval(() => {
      fetch('/api/v1/heartbeat');
    }, 5000);
  }

  componentWillUnmount() {
    clearInterval(this.timer);
  }
}

创建高阶组件( HoC , Higher-Order Component)

高阶组件,接受一个参数(至少有一个组件),返回一全新但组件

const HoC = (WrappedComponent) => {
    const WrappingComponent = (props) => (
        <div className="foo">
            <WrappedCompoent {...props} />
        </div>
    );
    return WrappingComponent;
};

继承方式的HoC(不推荐):

const HoC = (WrappedComponent) => {
    class WrappingComponent extends WrappendComponent {
        render() (
            const {user, ...otherProps} = this.props;
            this.props = otherProps;
            return super.render();
        }
    }
    return WrappingComponent;
};

应用:

组件之间通信

  • 父子之间
  • 兄弟之间
  • 其它之间

通信方式:

  • props(父到子,子到父用函数)
  • refs(比较笨重,尽可能不用)
  • callback(比如promise)
  • parent(兄弟组件之间,通过parent)
  • global veriable(很拙劣,一般用EventEmmiter)
  • redux

FAQ:

  • react如何处理动画呢,也是更新data? 传统的方式(css),更新state

  • immutable在diff中有什么应用场景和优点?

  • 如何保持数据的唯一性?减少state有什么好处么?

    最好将state集中到一处处理。

  • 那么key一般用什么呢?

    比如刚才举例的数组下标不行?最好别用,可以尝试利用元素标识符

  • 请求回调,setstate之前切换页面,有效解决warning的方式有哪些?

    在componentWillUnMount的时候在promise上包一层,加个cancel方法。