1

1. Reat简介

专注于视图层

React不是完整的MVC/MVVM框架,它专注于视图层,提供清晰,简洁的视图层解决方案。听起来和模板引擎很像,但是React又是一个包括view和controller的库
React不像其他框架提供很多复杂的概念和繁琐的API,它以Minimal API Interface为目标,只提供组件化相关的非常少量的API.

Vitrual DOM(虚拟DOM)

我们知道在页面中的结构对应着一个DOM树。在传统开发中,在更新页面的时候,需要手动的操作DOM。如图:

clipboard.png

但是,总所周知,操作DOM的代价是什么昂贵的。因为操作DOM性能消耗是很大的,而且这样的代码也很难维护(使用过jQuery的同学应该有所体会)。
在react中,React把真实DOM树转为JavaScript对象树,也就是所谓的虚拟DOM。

clipboard.png

在每次更新后,会重新计算Virtual DOM,并和上一次的Virtual DOM进行对比,对发生的部分进行批量更新。在React的生命周期中,提供了一个shouldComponentUpdate生命周期回调,通过判断可以减少数据变化后不必要的Virtual DOM的对比过程,提高性能。

但是进行虚拟DOM的比较也是需要消耗性能的,React还有另外一个亮点,就是方便和其他平台进行集成。

函数式编程

之前,一直以命令式编程为主,命令式编程解决的是做什么的问题,就像是给电脑下命令。而函数式编程,对应的是声明式编程。如果是人的思考方式,则是构建一个规则,然后应用该规则。

回到UI界面上,React把过去不断重复构建UI的过程抽象成了组件,且在给定参数的情况下约定渲染对应的UI界面。react能充分利用很多函数式方法去减少冗余代码。此外它本身就是简单函数,所以易于测试。可以说,函数式编程才是react精髓。

2. JSX语法

说到react大家肯定会想到JSX语法。React为方便view层组件化,承载了构建HTML结构化页面的职责。与一般的JavaScript模板语言有着异曲同工之处,但是不同的是,react是通过创建与更新虚拟元素来管理整个Virtual DOM的。

其中,虚拟元素可以理解为真实元素的对应,它的构建与更新都是在内存中完成,并不会渲染到真实的DOM中去。在React中创建的虚拟元素可以分为两类,DOM元素和组件元素

  • DOM元素

web页面是由一个个HTML元素嵌套组合而成,当使用JavaScript来描述这些元素的时候,这些元素可以被表示成JSON对象

<button class="btn btn-blue">
    <em>confirm</em>
</button>

其中包括了元素的类型和属性,如果转为JSON对象,那么依然包括元素的类型以及属性:

{
    type: 'button',
    props: {
        className: 'btn btn-blue',
        children: [{
            type: 'em',
            props: {
                children: 'confirm'
            }
        }]
    }
}

如上,我们就可以在JavaScript中创建Virtual DOM元素了。

在react中,到处都是可以复用的元素,这些元素并不是真实的实例,它只是让react告诉开发者想要在屏幕上显示什么。我们无法通过方法去调用这些元素,他们只是不可变的描述对象

  • 组件元素

我们封装一下上面的button按钮:

const Button = ({color, text}) => {
    return {
        type: 'button',
        props: {
            className: `btn  btn-${color}`,
            children: {
                type: 'em',
                children: text
            }
        }
    }
}

自然,我们要生成DOM元素中具体的按钮时,就可以方便的调用Button({color: 'blue', text: 'confirm'})来创建。

仔细思考这个可以发现,Button方法其实也可以作为元素而存在,方法名对应了DOM元素类型,参数对应了DOM元素属性。这样构建的元素就是自定义类型的元素,或者称为组件元素。我们用JSON结果来描述:

{
    type: Button,
    props: {
        color: 'blue',
        text: 'confirm'
    }
}

这也是react的核心思想之一。因为有了公共的表达方法,我们就可以让元素彼此嵌套。这些层层封装的组件元素,就是所谓的react组件。我们最终可以用递归的方式构建出完全的DOM树。

我们再看一个封装的更深的例子,为Button元素再封装一次,它由一个方法构建:

const dangerButton = ({text}) => {
    type: Button,
    props: {
        color: 'red',
        children: text
    }
}

直观的看,dangerButton从视觉上为我们定义了一个'危险的按钮',接着,我们可以轻松的运用,继续封装新的组件元素:

const deleteButon = () => ({
    type: 'div',
    props: {
        children: [{
            type: 'p',
            props: {
                children: 'Are you sure?',
            }
        }, {
            type: dangerButton ,
            props: {
                children: 'confirm'
            }
        }, {
            type: Button, 
            props: {
                color: 'blue',
                children: 'cancle'
            }
        }]
    }
})

如上,清晰的表示了一个功能模块。但是在结构复杂的时候,它就力不从心了。此时JSX语法出现。假如使用JSX表示:

const DeleteAccount = () => (
    <div>
        <p>are you sure?</p>
        <DangerButton>Confirm</DangerButton>
        <Button color="blue">Cancel</Button>
    </div>
)

如你所见,JSX 将 HTML 语法直接加入到 JavaScript 代码中,再通过翻译器转换到纯
JavaScript 后由浏览器执行。

JSX基本语法

JSX 的官方定义是类 XML 语法的 ECMAScript 扩展。它完美地利用了 JavaScript 自带的语法
和特性,并使用大家熟悉的 HTML 语法来创建虚拟元素。

  • XML基本语法

使用类 XML 语法的好处是标签可以任意嵌套,我们可以像 HTML 一样清晰地看到 DOM 树
状结构及其属性。
注意:定义标签时,只允许被一个标签包裹标签一定要闭合。

  • 元素类型

我们讲到两种不同的元素:DOM 元素和组件元素。对应规则是 HTML 标签首字母是否为小写字母,其中小写首字母对应 DOM 元素,而组件元素自然对应大写首字母。等到依赖的组件元素中不再出现组件元素,我们就可以将完整的 DOM 树构建出来了。

JSX 还可以通过命名空间的方式使用组件元素,以解决组件相同名称冲突的问题,或是对一
组组件进行归类。

const App = () => (
    <MUI.RaisedButton label="Default" />
)
  • 元素属性

class 属性改为 className;for 属性改为 htmlFor 。

  • JavaScript 属性表达式

属性值要使用表达式,只要用 {} 替换 "" 即可。

  • 展开属性

如果事先知道组件需要的全部属性,JSX 可以这样来写:
const component = <Component name={name} value={value} />;
如果你不知道要设置哪些 props,那么现在最好不要设置它:
const component = <Component />;
component.props.name = name;
component.props.value = value;
上述这样是反模式,因为 React 不能帮你检查属性类型(propTypes)。这样即使组件的属性
类型有错误,也不能得到清晰的错误提示。
这里,可以使用 ES6 rest/spread 特性来提高效率:

const component = <Component name={data.name} value={data.value} />;```
可以写成:

const component = <Component {...data} />`

3. React组件

React组件基本上由三个部分组成-属性,状态,生命周期

clipboard.png

react可以接受参数,也可以有自身状态,一旦接受到的参数或者自身状态改变,react组件就会执行相应的生命周期方法,最后渲染。

  • react组件的构建方法

react组件基本上由组件的构建方式,组件内的属性状态与生命周期方法组成。

(1) React.createClass
用 React.createClass 构建组件是 React 最传统、也是兼容性最好的方法。

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>
        );
    }
});

从表象上看, React.createClass 方法就是构建一个组件对象。当另一个组件需要调用 Button
组件时,只用写成 <Button /> ,就可以被解析成 React.createElement(Button) 方法来创建 Button实例,这意味着在一个应用中调用几次 Button,就会创建几次 Button 实例。

(2) 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>
        );
     }
}

这里的直观感受是从调用内部方法变成了用类来实现。与 createClass 的结果相同的是,调
用类实现的组件会创建实例对象.

React 的所有组件都继承自顶层类  React.Component 。它的定义非常简洁,只是初始化了
React.Component 方法,声明了  props 、 context 、 refs 等,并在原型上定义了  setState 和forceUpdate 方法。内部初始化的生命周期方法与  createClass 方式使用的是同一个方法
创建的。

(3)无状态函数
使用无状态函数构建的组件称为无状态组件。

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

无状态组件只传入 props 和 context 两个参数;也就是说,它不存在 state ,也没有生命周期方法,组件本身即上面两种 React 组件构建方法中的 render 方法。不过,像 propTypes 和
defaultProps 还是可以通过向方法设置静态属性来实现的。在适合的情况下,我们都应该且必须使用无状态组件。无状态组件不像上述两种方法在调用时会创建新实例,它创建时始终保持了一个实例,避免了不必要的检查和内存分配,做到了内部优化。


fsrookie
2.9k 声望256 粉丝

目前很多文章都是摘抄记录其他教程。见谅。