React初识

作者: 我是那只喵 | 来源:发表于2017-08-27 21:50 被阅读59次

    React是一个JavaScript语言的工具库,起源于Facebook的一个内部项目,最初用来构建Instagram的网站,并于2013年5月开源。

    安装

    对于React初学者而言,React官方提供了一个工具——create-react-app,目的是将开发者人员从配置中解放出来,从而能快速的进入到React应用的开发中。

    具体安装过程如下:


    npm install -g create-react-app   全局安装 creat-react-app 命令

    create-react-app   my-app          使用命令在当前目录下创建一个名为my-app的react应用

    cd my-app                                   进入my-app项目文件夹

    npm-start                                     执行该命令


    之后会启动一个开发者模式的服务器,同时浏览器自动打开一个网页,指向http://localhost:3000/

    界面如下图所示:

    http://localhost:3000/

    第一个React应用就这样诞生了~

    生成的文件夹目录结构,如下图所示:

    项目目录结构

    开发过程中,我们主要关注src目录中的内容,而我们所创建项目的入口便是src/index.js文件,这里面的代码做了这样一件事,它渲染了一个名为App的组件,将其挂在到了id为root的DOM节点上。

    src/index.js

    同时我们再来看看在src/App.js中,App组件是怎样创建的:

    src/App.js

    可以看到代码的第一行我们从react库中引入了React和Component,Component作为所有组件的基类,提供了很多组件共有的功能,之后创建了一个名为App的组件类,然后通过export default App将其导出,并在在src/index.js中通过import导入,最后加以使用。

    UI=render(data)

    React的理念归结为一个公式:UI=render(data)

    用户看到的UI界面,是一个函数——render的执行结果,只接受数据——data作为参数。这是一个纯函数,即输出只依赖于输入的函数,两次函数的调用如果输入相同,那么输出也绝对相同。如此一来,最终的用户界面,在render函数确定的情况下完全取决于输入数据。

    因此对于开发者而言,重要的是区分,哪些是render,哪些是data,想要改变UI,要做的就是更新data

    ——《深入浅出React和Redux》

    Virtual DOM

    在上一节中,我们似乎很容易得出这样一个结论,每次更新UI界面,react都要进行重新渲染,这样会不会使得效率低下呢?

    事实上并不会这样,React利用Virtual DOM让每次渲染都只渲染最少的DOM元素。Virtual DOM是对DOM树的抽象,它并不触及浏览器部分,只是存在于JavaScript空间的树形结构,每次在渲染React组件,React会对前后两次产生的Virtual DOM进行比较,最后只有发生了改变的地方会被重新渲染。

    总而言之,React利用函数式编程的思维来解决用户界面渲染的问题,强制所有组件都以数据驱动渲染的模式进行开发。

    JSX

    要学习react首先就要了解JSX,它是JavaScript的一种扩展语法,使我们能够在JavaScript中编写类似HTML的代码。

    JSX 的基本语法规则:遇到 HTML 标签(以<开头),就用 HTML 规则解析;遇到代码块(以{开头),就用 JavaScript 规则解析。

    我们可以用{}将任意的JavaScript表达式嵌入到JSX中。

    JSX注释也很简单,一般用花括号包围:


    {/* 这里是注释 */}


    React组件

    React允许将代码封装成组件,然后像插入普通HTML标签那样,插入使用我们自定义的组件。自定义的组件要以大写字母开头,这样才能被识别为React组件。

    组件也可以在标签中插入任意属性,特别注意:

    class属性需要写成className,for属性需要写成htmlFor,这是因为class和for是 JavaScript 的保留字。对于属性的访问,可以通过this.props.xxx来访问对应的xxx属性。

    每个组件必须有一个render方法,用于输出组件自身,同时输出的组件只能包含一个顶层标签。

    举个例子:

    名为Demo的组件

    在上面的例子中,我们创建了一个名为Demo的React组件,用来在界面输出Hello,my name is xxx的信息。而this.props.name就是对组件调用时传入的name属性的访问。最终界面输出如下图所示:

    输出结果

    props & state

    React组件的数据分为两种——props和state。其中props是组件的对外接口,state则是组件的内部状态。它们任何一个的改变都会引发组件的重新渲染。

    props

    props是从外部传递给组件的数据,在上一节的例子中,name就是传递给Demo组件的一个外部props,同时在组件内部,通过this.props.nam访问,这样我们就能很轻易的将外部的数据传递给组件内部。那相反,如果我们想要把内部的数据传递给外部该怎么办呢?

    同样也是使用props,因为props的类型不限于纯数据,它还可以是函数,所以我们可以定义一个函数类型的props,相当于父组件交给了自组件一个回调函数。自组件在适当的时候调用这个函数,并传入必要的参数,父组件接收到参数后,对参数进行相应的逻辑处理。

    举个例子:

    Parent父组件

    在Parent父组件中,我们定义了一个changeResult的函数,它接收一个参数,最后计算出参数的二次幂,将结果result显示在界面中。同时,接收的这个参数是来自于Child组件,父组件在调用子组件时,将changeValue这个方法作为子组件的props传给了子组件。

    Child子组件

    在Child子组件中,点击button会使得子组件中value值加1,并在此时调用this.props.changeValue,将新的value值传给父组件Parent。

    最终的效果如下图所示:

    初始值 点击button后的值

    protoType可以用来规范组件的接口,定义自己可以接收哪些类型或者符合哪些规则的prop。以上面的Child组件来说,我们要求它接收的changeReault是一个函数:


    Child.propTypes = {

    changeResult: PropTypes.func

    };


    上面的代码要求changeResult这个prop必须是个函数的类型。


    state

    state代表组件的内部状态,因为组件不能修改传入的props,所以为了记录自身的状态变化就得用到state。

    组件的state通常在组件的构造函数中初始化,且state必须是一个对象。


    constructor(props){

        super(props);

        this.state = {

            value: 0

        }

    }


    React还提供了一个defaultProps功能,用来制定默认的prop值,在特定的props值不是必须且没有被传入的情况下,会使用这个指定的默认值。


    Child.defaultProps = {

        changeResult: f => f      //默认是一个什么都不做的函数

    }


    对state的修改不能直接通过this.state.xxx来修改,需要调用this.setState({xxx: newValue});来修改。因为this.setState会驱动组件进行重新渲染,而如果直接用this.state.xxx来修改,并不能触发。

    React组件的生命周期

    React定义了组件的生命周期,可分为一下三个过程:


    装载过程:Mount —— 组件第一次在DOM树中渲染的过程

    更新过程:Update —— 组件被重新渲染的过程

    卸载过程:Unmount —— 组件从DOM中删除的过程


    在不同的生命周期中,React会一次调用组件的一些函数,这些函数被称为生命周期函数。

    装载过程

    当组件第一次被挂载的时候会依次调用以下函数:


    constructor

    componentWillMount

    render

    componentDidMount


    这几个函数从函数名就大概知道是什么了。

    constructor构造函数,非必需,无状态组件可以不使用。在存在的情况下,constructor是生命周期中被调用的第一个函数,在这里我们可以初始化state,同时绑定成员函数的this环境。

    componentWillMount,非必需,render函数之前被调用,与componentDidMount对称。同时componentWillMount可以在服务端和浏览器端被调用。

    render,必须,它是React组件中最重要的函数,它返回一个JSX描述的结构,之后React来操作渲染过程,render函数是一个纯函数,完全根据this.state和this.props 来决定返回结果,因此在render函数中调用this.setState是错误的。

    componentDidMount,非必需,只能在浏览器端被调用,componentDidMount函数并不是紧跟render函数后面被调用,它被调用时,render函数返回的东西已经引发来渲染,组件已经被“装载”到了DOM树上,此时可以放心的获取渲染出来的任何DOM,也可以通过ajax获取数据来填充组件的内容。

    更新过程

    更新过程会调用如下生命周期函数:


    componentWillReceiveProps

    shouldComponentUpdate

    componentWillUpdate

    render

    componentDidUpdate


    但并不是所有更新过程都会调用以上所有函数。

    我们先来看看哪些情况会触发更新过程(默认shouldComponentUpdate返回true)

    1. 父组件的render函数被调用

    2. this.setState调用,但不是每调用一次就更新一次,有时react会合并操作,并最后一次性调用render更新

    3. this.forceUpdate强制更新

    而在这些情况下会依次调用的生命周期函数,如下图所示:

    更新路径

    componentWillReceiveProps当父组件调用render时会触发,而不是仅仅只有props发生改变时才触发。

    shouldComponentUpdate默认返回true,如果返回false则立即停止更新,如果恰当使用shouldComponentUpdate来控制是否继续更新,可以有效提高效率。

    componentWillUpdate,当shouldComponentUpdate返回true,紧接着调用componentWillUpdate,之后是render,再之后是componentDidUpdate。

    注意:通过this.setState函数引发的更新,并不是立刻改变state的值,其实,在调用shouldComponentUpdate时state的值依然是this.setState执行之前的值。

    卸载过程

    componentWillUnmount,当react组件需要从DOM树上删除掉之前会调用它,所以这个函数适合做一些清理工作。比如,在componentDidMount中用非react的方法创造了一些DOM元素,如果撒手不管的话会造成内存泄漏,那就需要在componentWillUnmount中将这些DOM卸载掉。

    参考文章和书籍

    http://www.jianshu.com/p/4784216b8194

    《深入浅出React和Redux》

    相关文章

      网友评论

        本文标题:React初识

        本文链接:https://www.haomeiwen.com/subject/vdgvdxtx.html