React文档学习重点

React利用虚拟DOM(Virtual DOM),解决了传统方式操作DOM时的诸多问题。

HTML DOM问题

Web网站操作DOM时的性能问题导致交互动画出现卡顿。

DOM问题根源

Web应用基于DOM,浏览器解析html时,在内存中生成DOM结构、接受CSS对样式进行调整,这个过程受html结构和样式复杂性影响极大。DOM操作的同步特性,降低了浏览器解析html文档的整体效率,一旦出现阻塞,整个页面就失去响应。

DOM问题解决方案

方案的出发点

浏览器渲染html的频率60FPS(16毫秒/帧),js能否在16毫秒完成对DOM的操作,取决程序的复杂性。因此,产生跳帧的问题既不确定也不可避免。用户感受到不流畅或不连贯也就再所难免。加上网页样式中的大部分样式属性都是由CPU直接处理,无法利用高效的GPU图形加速技术。

去DOM方案

手机App FlipBoard给出一个了前无古人的方案,抛弃DOM,把html当作图片进行渲染。将整个网站用HTML5 <canvas> 标签绘制成图像(通过JavaScript),<canvas> 元素本身没有图形绘制能力,它仅仅是图形容器。因为一方案在图形绘制方面充分利用了硬件加速技术,所以流畅性方面与Native app并无二致。

FlipBoard方案存在很大的争议,canvas只是一种位图,更不存语义。没有CSS动态效果、超链接功能、不具备自适应的特性、无法通过搜索引擎进行检索。所以适用的场景非常窄。

Mozilla多线程方案

Mozilla开发了Servo项目,一个多线程并行处理的浏览器。多线程浏览器、一个网页由多个线程处理,以保证主线程能在16毫秒内完成。

异步操作DOM方案

当JavaScript对DOM进行操作时,不再采用同步方式,而是通过事件把它交给Event Loop处理单元。

React Virtual DOM解决方案

在React中每个组件都有一个状态,这是一个可观察的状态,由于能观察到数据何时发生变化,所以,React知道何时重新渲染。React利用diff算法检查Virtual DOM与DOM之间的差异,决定是否需要重新渲染。

React项目历史

React源于Facebook的内部项目,旨在为Instagram网站开发一个JavaScript MVC框架。2013年5月对React进行了开源。React设计独特、性能出众、代码逻辑清晰、备受众多开发者关注。最终,React变成了在Web应用方面,前后端通用的UI解决方案。编写一套UI代码,能够运行于多种客户端上。

React学习环境

学习React语法时,可以借助在线编码环境快速进入学习。

https://codesandbox.io/s/new

https://codepen.io/gaearon/pen/oWWQNa?editors=0010

React语法概述

React从表现上来看是一种js与html混写的语法。所以React JSX代码块type="text/babel“。React除了自己的核心功能包,还包含一个Browser.js,用于把JSX语法转成JavaScript。

ReactDOM.render(<App />, rootElement);

ReactDOM.render是React最常用的接口。用于把模板转成html插入到DOM中。

JSX语法

在JSX语法中书写html是不需要加引号的,而html也可以直接引用JS对象。

function App() {
  var list = ['Lee', 'Rain', 'Nick'];
  return (
    <div className="App">
      <h1>Hello</h1>
      <img src='/my-profile' />
  {
    list.map(function(n){
          return <span>{n}</span>
        })
  }
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));

把JSX与JS、html作一个简单的比较说明:

App函数的第一行,声明了一个装有数据的数组。第二行是个return语句。前两行都基本的js语法。

第三行是一个html标签,这个标签是模板的根元素,一个JSX块只能有一个根元素。html中的class属性应改名为className。

第四行是一个标准的html元素写法。

第五行是一个img标签,JSX语法要求标签要有完整的关闭标识,所以,img结束位置的斜杠(/)不能少。

第六行开始引用js变量,用大一对括号进行标记。

第七行是一个js语法,只不过结尾处不需要分号(;),加入分号编译反而不能通过。

第八行引入一个html元素,元素中通过大括号引用了js变量。

最后一行把App函数做为一个标签进行引用,通过ReactDOM.render方法插入到DOM中。

由于React开发者相对比较活跃,版本随时间推移改动比较大,因此,示列中React API的用法可能与后续版本存在差异。学习React API,最佳方式是查看React文档。

www.reactjs.org/docs

React 组件(component)

React允许将函数与html元素封装成组件(component),最终当作HTML标签进行引用。html标签中的属性可以做为参数传给组件。

function FancyButton(props) {
  return (
    <button className="FancyButton">
      {props.says}
    </button>
  );
}

ReactDOM.render(<App says='word'></App>, document.getElementById("root"));

React children

如果把React组件当作html标签,那么,它就该有html所有的特点,比如拥有子元素。事实也确实如此。

function FancyButton(props) {
  return (
    <button className="FancyButton">
      {props.children}
    </button>
  );
}

ReactDOM.render(<App says='word'><h2>song</h2></App>, document.getElementById("root"));
https://reactjs.org/docs/forwarding-refs.html#forwarding-refs-to-dom-components

React PropTypes

如果需要对属性进行类型限制,可以通过PropTypes进行定义。

import PropTypes from 'prop-types';

class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

Greeting.propTypes = {
  name: PropTypes.string
};
https://reactjs.org/docs/typechecking-with-proptypes.html#___gatsby

React获取DOM

React使用虚拟DOM(virtual DOM),如果需要获取html DOM,可以通过ref给html元素起一个名字,在程序中通过refs['hefName']方式对元素进行操作。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}
https://reactjs.org/docs/refs-and-the-dom.html

React State

React每个组件都有状态,状态发生变化,DOM就会被重新渲染。

 <button onClick={() => this.setState({ count: this.state.count + 1 })}>
    Click me
  </button>
https://reactjs.org/docs/hooks-state.html

React forms

form表单出现的地方,往往都有复杂的用户交互需求。如果依赖React提供的API,很多功能都会缚手缚脚,这时就要回归html本身了。比如:在html元素上定义事件,然后,调用React的一些属性。

https://reactjs.org/docs/forms.html

React组件生命周期

React组件生命周期包括三个阶段,每个生命周期都有对应的处理方法可供使用。

Mounting

当创建组件实例,将其插入DOM时,将顺序调用以下方法:

constructor()
static getDerivedStateFromProps()
render()
componentDidMount()

Updating

当props或state被更改后引发更新,重新渲染组件时,将顺序调用以下方法:

static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()

Unmounting

当从DOM中删除组件时调用此方法:

componentWillUnmount()
https://reactjs.org/docs/react-component.html#the-component-lifecycle

React错误处理(Error Handling)

在渲染期间、生命周期方法或子组件的构造函数发生错误时,将调用以下方法。

static getDerivedStateFromError()
componentDidCatch()
https://reactjs.org/docs/react-component.html#the-component-lifecycle

React使用Ajax渲染组件

在React中,如果需要使用Ajax获取数据渲染组件,应在componentDidMount方法中,发起AJAX请求,通过setState更新组件。

https://reactjs.org/docs/faq-ajax.html#example-using-ajax-results-to-set-local-state