【React】知识梳理:React特性

1,568 阅读7分钟

什么是react?

  • React 是一个用于构建用户界面的 Javascript 库。
  • React 主要用于构建UI,可以认为 React 是 MVC 中的 V(视图)。
  • React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,于 2013 年 5 月开源。
  • React 拥有较高的性能,代码逻辑非常简单,现在有越来越多的人开始关注和使用它。

react特性

声明式设计

React采用声明范式,可以轻松描述应用。无须使用变量,避免了创建和修改状态,使最终的代码简单易于维护。(区别于命令式编程,它的特点就是告诉计算机做什么,但是没有怎么做)

//命令式编程
var array = [1,2,3,4,5]
var total = 0
for(var i = 0; i < array.length; i++) {
  total *= numbers[i]
}
console.log(total) //=> 120//声明式编程
var array = [1,2,3,4,5]
var total = array.reduce(function(sum, n) {
  return sum * n
});
console.log(total) //=> 120//相比于命令式编程,声明式编程最大的特点是没有"if"、"for"这类的控制语句,而是直接给一个函数,并且声明一个变量接收函数执行结果,让计算机把数据当作参数放进去执行一遍。

高效(虚拟DOM)

React通过对DOM的模拟(虚拟DOM,Virtual DOM),最大限度地减少与DOM的交互。(核心是通过DIFF算法比较改变前后的DOM区别,然后用最少的DOM语句对DOM进行操作)

  1. React非常快速是因为它从不直接操作DOM。
  2. 虚拟DOM是在DOM的基础上建立了一个抽象层,对数据和状态所做的任何改动,都会被自动且高效的同步到虚拟DOM,最后再批量同步到DOM中。
  3. 在React中,render执行的结果得到的并不是真正的DOM节点,而仅仅是JavaScript对象,称之为虚拟DOM。
  4. 虚拟DOM具有批处理和高效的Diff算法,可以无需担心性能问题而随时“刷新”整个页面,因为虚拟DOM可以确保只对界面上真正变化的部分进行实际的DOM操作。

传统App(innerHTML:render html字符串 + 重新创建所有 DOM 元素):

img

React App(虚拟DOM:render 虚拟DOM + diff + 更新必要的 DOM 元素):

img

虚拟DOM的原理

React会在内存中维护一个虚拟DOM树,对这个树进行读或写,实际上是对虚拟DOM进行。当数据变化时,React会自动更新虚拟DOM,然后将新的虚拟DOM和旧的虚拟DOM进行对比,找到变更的部分,得出一个diff,然后将diff放到一个队列里,最终批量更新这些diff到DOM中。

img

创建虚拟DOM的两种方式:

//纯js(一般不用)
React.createElement('h1', {id:'myTitle'}, title)
​
//JSX
<h1 id='myTitle'>{title}</h1>
<div id='example1'></div>
<div id='example2'></div>

灵活

React可以与已知的库或框架很好地配合。

Ant Design

一个可以用来快速设计后台 / 内部应用的 UI 库。它拥有一个社区、大量支持文档,还有一个带有预制模板的单独项目AntDesignPro。

React-Bootstrap

一个具有 Twitter 的 Bootstrap 的观感的 React 组件库。它的极简风格在社区中有很高的热度。

React-Transition-Group

React-Transition-Group提供了用于定义动画的简单组件,该库并未定义样式本身,而是以有用的方式操作DOM,从而使过渡和动画的实现更加舒适。

React-Redux

React-Redux是Redux的官方React绑定库。它能够使你的React组件从Redux store中读取数据,并且向store分发actions以更新数据。

JSX

JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但建议使用它。

JSX 即Javascript XML,它是对JavaScript 语法扩展。React 使用 JSX 来替代常规的 JavaScript。你也可以认为JSX其实就是JavaScript。当遇到<,JSX就当HTML解析,遇到{就当JavaScript解析。

JSX优点:

  • JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
  • 它是类型安全的,在编译过程中就能发现错误。
  • 使用 JSX 编写模板更加简单快速。
  • JSX 可以防止注入攻击。(React DOM 在渲染所有输入内容之前,默认会进行转义。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(cross-site-scripting, 跨站脚本)攻击)

使用JSX注意事项:

  • 支持表达式书写,只需要将表达式写到{}内即可。
ReactDOM.render(
    <div>
      <h1>{1+1}</h1>
    </div>
    ,
    document.getElementById('example')
);
  • 不能使用if else,可以使用三元运算表达式替代。
ReactDOM.render(
    <div>
      <h1>{i == 1 ? 'True!' : 'False'}</h1>
    </div>
    ,
    document.getElementById('example')
);
  • JSX 允许在模板中插入数组,数组会自动展开所有成员。也可以利用数组的map属性来对其进行数据列表渲染。
var arr = [
  <h1>test1</h1>,
  <h2>test2</h2>,
];
ReactDOM.render(
  <div>{arr}</div>,
  document.getElementById('example')
);
​
var arr=["你是风儿","我是沙","缠缠绵绵到天涯"];
var list=arr.map(function(v){
       return <h3>{v}</h3>
})
 ReactDOM.render(
       <div>
           {list}
       </div>,
       document.querySelector("#wrap")
)
  • JSX 语法上更接近 JavaScript 而不是 HTML,所以 React DOM 使用 camelCase(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。

例如,JSX 里的 class 变成了 className,而 tabindex 则变为 tabIndex

  • JSX中,可以通过使用引号,来将属性值指定为字符串字面量。也可以使用大括号,来在属性值中插入一个 JavaScript 表达式。
const element = <div tabIndex="0"></div>;
​
const element = <img src={user.avatarUrl}></img>;

组件化

通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。

React 的组件可以定义为 函数(function,无状态组件)或class(继承React.Component,有状态组件) 的形式。

//函数组件
function HelloMessage(props) {
    return <h1>Hello World!</h1>;
}
​
//ES6 class 定义的组件
class Welcome extends React.Component {
  render() {
    return <h1>Hello World!</h1>;
  }
}

函数组件和类组件的区别

  • 两者最明显的不同就是在语法上,函数组件是一个纯函数,它接收一个props对象返回一个react元素。而类组件需要去继承React.Component并且创建render函数返回react元素,这将会要更多的代码,虽然它们实现的效果相同。
  • 类组件使用的时候要实例化,而函数组件直接执行函数取返回结果即可。
  • 函数组件不能访问this对象,无法访问生命周期的方法,没有状态state
  • 类组件有this,有生命周期,有状态state
  • 无状态(函数)组件只能访问输入的props,同样的props会得到同样的渲染结果,不会有副作用。
  • 函数组件的性能比类组件的性能要高,不知道用什么组件类型时,推荐用React.FC

单向响应的数据流

React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。

React 单向数据流(自顶向下),数据主要从父节点传递到子节点(通过props)。如果顶层(父级)的某个props改变了,React会重渲染所有的子节点。

父子组件沟通

  • 父组件更新组件状态,传递props,子组件更新。
  • 子组件更新父组件状态 ,父组件传递回调函数给子组件, 子组件调用触发。
class Child extends React.Component{
  constructor(props){
    super(props);
    this.state = {}
  }
  
  render(){
    return (
      <div>
        {this.props.text}
        <br />
        <button onClick={this.props.refreshParent}>
            更新父组件
        </button>
      </div>
    )
  }
}
class Parent extends React.Component{
  constructor(props){
    super(props);
    this.state = {}
  }
  refreshChild(){
    return (e)=>{
      this.setState({
        childText: "父组件沟通子组件成功",
      })
    }
  }
  refreshParent(){
    this.setState({
      parentText: "子组件沟通父组件成功",
    })
  }
  render(){
    return (
      <div>
        <h1>父子组件沟通</h1>
        <button onClick={this.refreshChild()} >
            更新子组件
        </button>
        <Child 
          text={this.state.childText || "子组件未更新"} 
          refreshParent={this.refreshParent.bind(this)}
        />
        {this.state.parentText || "父组件未更新"}
      </div>
    )
  }
}

兄弟组件沟通

当两个组件有相同的父组件时,就称为兄弟组件。按照React单向数据流方式,需要借助父组件进行传递,通过父组件回调函数改变兄弟组件的props

  • 通过props传递父组件回调函数。
  • 如果组件层次太深,React提供了一种上下文方式(挺方便的),可以让子组件直接访问祖先的数据或函数,无需从祖先组件一层层地传递数据到子组件中。
class Brother1 extends React.Component{
  constructor(props){
    super(props);
    this.state = {}
  }
  
  render(){
    return (
      <div>
        <button onClick={this.props.refresh}>
            更新兄弟组件
        </button>
      </div>
    )
  }
}
class Brother2 extends React.Component{
  constructor(props){
    super(props);
    this.state = {}
  }
  
  render(){
    return (
      <div>
         {this.props.text || "兄弟组件未更新"}
      </div>
    )
  }
}
class Parent extends React.Component{
  constructor(props){
    super(props);
    this.state = {}
  }
  refresh(){
    return (e)=>{
      this.setState({
        text: "兄弟组件沟通成功",
      })
    }
  }
  render(){
    return (
      <div>
        <h2>兄弟组件沟通</h2>
        <Brother1 refresh={this.refresh()}/>
        <Brother2 text={this.state.text}/>
      </div>
    )
  }
}

全局事件

当项目复杂,组件间层次越来越深,可以使用全局事件来进行组件间的通信,官网推荐Flux(Facebook官方出的),还有Relay、Redux、trandux等第三方类库。这些框架思想都一致,都是统一管理组件state变化情况,达到数据可控目的。