React是一个用于构建用户界面的Javascript库,其核心思想是声明式渲染(Declarative)组件化(Component-Based)。

声明式渲染

Web渲染分为两种方式,声明式渲染 and 命令式渲染。

  • 命令式:

    1. // 命令式关注如何做(how)
    2. let numbers = [1,2,3,4,5]
    3. let doubled = []
    4. for(let i = 0; i < numbers.length; i++) {
    5. let newNumber = numbers[i] * 2
    6. doubled.push(newNumber)
    7. }
    8. console.log(doubled) //=> [2,4,6,8,10]
  • 告诉程序怎么做,能否达成结果取决于开发者的设计。

  • 声明式:只告诉程序想要什么结果,如何达成由程序保证,开发者不用关心。

    1. // 声明式关注做什么(what)
    2. let numbers = [1,2,3,4,5]
    3. let doubled = numbers.map(function(n) {
    4. return n * 2
    5. })
    6. console.log(doubled) //=> [2,4,6,8,10]

    组件化

    现代Web应用页面复杂,通常包含诸多业务模块。如果将页面中所有的逻辑放在一起,处理起来会变得非常复杂,也不利于后续的扩展和维护。
    React的另一大核心思想就是组件化,目的就是拆分业务逻辑实现复用、并且减少代码冗余。

    一个简单的实例

    这里通过一个简单的组件来快速了解React,以及建立起对 React 的一个总体认识。

    1. import React, { Component } from 'react';
    2. import { render } from 'react-dom';
    3. //render渲染函数是react-dom
    4. class HelloWorld extends Component {
    5. render() {
    6. return <div>Hello {this.props.name}</div>;
    7. }
    8. }
    9. // 加载组件到 DOM 元素 mountNode
    10. render(<HelloWorld name="Lihao" />, document.getElementById('#root'));

    React大体包含以下概念:

  • 组件

组件是独立的、可重用的代码。组件有两种类型,类组件(Class)函数式组件(Function)

  1. class HelloWorld extends Component { //类式组件
  2. render() {
  3. return <div>Hello {this.props.name}</div>;
  4. }
  5. }
  6. function HelloWorld(props) { //函数式组件
  7. return <div>Hello World!{props.name}</div>;
  8. }
  9. // 加载组件到 DOM 元素 mountNode
  10. render(<HelloWorld name="Lihao" />, document.getElementById('#root'));
  11. //一些区别&联系
  12. #1 函数式组件没有自己的this
  13. #1.1Function Component渲染到页面会经过的babel的转译,在函数内部默认开启严格模式
  14. #1.2严格模式(use strict)下,禁止自定义函数的this指向window
  15. #2 组件属性
  16. #2.1 组件实例对象,包含props state refs三大属性
  17. #2.2 props: 使用组件标签<HelloWorld attr1="attr1" attr2={attr2}/>
  18. attr1属性传递的是字符串'attr1',attr2传递的属性是变量attr2
  19. #2.3 state: 组件的内部状态集合,用于保存数据。state的改变驱动着页面的渲染
  20. #2.4 refs: 组件内部的引用集合(reference set),收集组件内部被ref标记的标签或者
  21. 其他组件,以供使用
  • JSX(Javascript XML)

JSX是JS的语法扩展,支持在html标签里插入js表达式来创建虚拟DOM。

  1. //基本形式 html标签和js代码的混合
  2. return <div>Hello World!{props.name}</div>;
  3. #1 JSX必须严格闭合
  4. <div> //错误
  5. <div/>//正确
  6. <div></div>//正确
  7. #2 JSX标签可以被当作一个JS变量
  8. let attr = <div>ddd</div>
  9. let container = <div>{attr}</div>
  10. #3 在JSX中使用变量
  11. let name = "test";
  12. <div>{name + "666"}</div>
  13. #4 在JSX中使用函数
  14. let names = ['Alice', 'Emily', 'Kate'];
  15. <div>
  16. {
  17. names.map(function (name) {
  18. return <div>Hello, {name}!</div>
  19. })
  20. }
  21. </div>
  22. #5 在JSX中不能使用if语句 使用三元运算符替代
  23. <div className={this.state.isComplete ? 'is-complete' : ''}></div>
  24. #6 使用...运算符
  25. let props = {};
  26. props.foo = x;
  27. props.bar = y;
  28. let component = <Component {...props} />;
  29. 等价于
  30. let component = <Component foo={props.foo} bar={props.bar} />;
  31. #7 JSX注释
  32. <div> {/* dddd */} </div> //注释JS
  33. <input
  34. name="email" //ddd //注释属性 注释多行属性/* */
  35. placeholder="ddd"/>
  36. //JSX只是React.createElement(component,props,children)函数的语法糖。
  • 虚拟DOM

当组件状态 state 有更改的时候,React 会自动调用组件的 render 方法重新渲染整个组件的 UI。 render 方法返回的结果并不是真实的DOM节点,而是轻量级的Javascript对象,我们称之为虚拟DOM。
当然如果真的这样大面积的操作 DOM,性能会有很大的问题,所以 React 实现了Virtual DOM,组件 DOM 结构就会被映射到这个 Virtual DOM 上。React 在这个 Virtual DOM 上实现了一个 diff 算法,当要重新渲染组件的时候,会通过 diff算法 寻找到要变更的 DOM 节点,再把这个修改更新到浏览器实际的 DOM 节点上,所以实际上不是真的渲染整个 DOM 树。这个 Virtual DOM 是一个纯粹的 JS 数据结构,所以性能会比原生 DOM 快很多。

  • 单向数据流

单向数据流,当前组件的stateprops的形式流动时,只能流向组件树中比自己层级更低的组件。也就是只能从父节点传递到子节点(通过props)。
UI = render(state)界面(UI)和状态(state)的关系,即UI依赖于state的变化

参考

  1. https://segmentfault.com/a/1190000007463108 React核心思维
  2. http://caibaojian.com/react/ React文档
  3. https://segmentfault.com/a/1190000006832035 JSX简介
  4. https://juejin.cn/post/6844904165026562056 虚拟DOM and diff算法
  5. https://www.zhihu.com/question/29504639 理解虚拟DOM
  6. https://zhuanlan.zhihu.com/p/362539108 精读《DOM diff 原理详解》