[ 一块儿学React系列 -- 1 ] 信笔说JSX

本篇算是[一块儿学React系列]真正意义上的第一篇文章。笔者忽然想开这个系列文章已是酝酿了好久,不是由于本身对React有多深的理解,相反笔者对React仍停留在使用的层面,说到深刻理解的话谈不上,科普的话算勉强;由于笔者是React的忠实粉丝,有计划得深刻学习React也是本身在前端技术领域进一步发展的第一站。因此本系列文章更可能是笔者一边学习一边分享学习心得的文章,算不上散播知识散播爱也达不到网上大佬文章的高度。只想和在座的每一位学习React的同仁一块儿学习,一块儿进步。其次本系列文章并不会过多得谈及高级概念或者专业词汇(由于笔者也懒得去理解它们,很累),因此本系列文章将大篇幅使用浅显易懂的词句分享笔者的学习心得。css

JSX初识

JSX是个好东西啊!!!
做为React的核心之一, JSX语法深得React Developer的喜好。首次接触它的人可能会被这个JSX词给吓到,认为这会是一个很难学习的东西然而事实并非残酷的反而是宁人欣慰的, FaceBook选择JSX做为React的首选开发语法契合React自己组件化的原则, 缘由是JSX是将 XMLJavaScript 融合而成的一种新的结构性语法, 能够用写XML的方式写JavaScript, 使得用JSX写组件更为便捷、结构更加清晰;举个例子:html

若是咱们想写以下的结构的组件前端

let comp = (
    <ul class="list">
       <li>one</li>
       <li>two</li>
    </ul>
)

JSX的写法与上面一致,只是须要将class改为className(由于class是html的保留字,JSX中须要使用className代替)node

而JavaScript的写法比较繁琐:react

let li1 = React.createElement('li', null, 'one');
let li2 = React.createElement('li', null, 'two');
let comp = React.createElement('ul', { className: 'list' }, li1, li2);

能够看出,使用JSX写组件方便的不是一点半点。点个赞!!webpack

据了解JSX并非Facebook独创,只是被Facebook发扬光大;
其次开发React并不仅能用JSX, TypeScript能够了解下。

其次,由于JSX写出来的代码并不能直接在目前任何一款浏览器上运行,所以在运行前须要预先使用工具把它翻译成浏览器所能识别的ES5代码,目前主流的是使用 WebPack + Babel 进行编译、打包。使用create-react-app搭建的项目中能够看到相关的WebPack配置文件(须要先运行 npm run eject 将文件释放出来,配置文件在 config 目录中), 打开配置文件能够看到这么一段git

// Process JS with Babel.
  {
    test: /\.(js|jsx|mjs)$/,
    include: paths.appSrc,
    loader: require.resolve('babel-loader'),
    options: {
      
      // This is a feature of `babel-loader` for webpack (not Babel itself).
      // It enables caching results in ./node_modules/.cache/babel-loader/
      // directory for faster rebuilds.
      cacheDirectory: true,
    },
  },

能够看出Webpack处理 js | jsx | mjs类型文件的时候用babel-loader进行翻译,最终生成浏览器可直接运行的ES5代码。web

JSX写法介绍

写JSX代码,笔者最大的体会就是:不是在HTML中写JavaScript就是在JavaScript中写HTML。虽然很狗血,可是真的是这样。下面一个一个看:npm

写组件

React中最简单的组件能够简单到什么程度?答案是就好像写一个HTML中的DOM节点同样数组

<h1>Hello World</h1>

这个在React体系中就算一个最简单的组件,是否是和写HTML很像?由于编译器在遇到<>会将该对象当作组件解析,遇到{}会当作JavaScript解析。因此这也是为何能够想在HTML中写js同样,举个例子:

function title(){
    const name = 'World';
    return (
        <h1>Hello {name}</h1>
    )
}

那么此时这个方法返回的组件就是

<h1>Hello World</h1>

是否是很简单呢?

固然React也支持编写复杂组件,方法有两种:
第一种是:

import React from 'react';

const Demo = React.createClass({
  render() {
    return (
      <div></div>
    );
  }
});
export default Demo;

另外一种是使用ES6中class的写法,推荐该写法

import React, {Component} from 'react';

class Demo extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div></div>
        );
    }
}
export default Demo;

写JavaScript代码

上面有提到过在组件中的{}里写JavaScript, 这里笔者主要说起两个地方:
第一个:
由于JSX本质上也是写js,所以能够像常规使用变量同样在{}中使用变量(只要能访问到),好比咱们写以下一个组件:

import React, {Component} from 'react';

class Demo extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        const age = 26;
        return (
            <div>明年个人年龄是:{age + 1} 岁</div>
        );
    }
}

export default Demo;

此时的展现内容是:

clipboard.png

能够看出,咱们不只能够在{}访问某变量,还能够作逻辑处理。

第二个:
能够在组件的{}中访问该组件的this对象。本文不对该对象进行介绍,后续会有相关博客。不过笔者想说这个this很重要, 有了它能够作不少事。写例子吧, 咱们将刚刚例子中的age变量放在this中试一下:

import React, {Component} from 'react';

class Demo extends Component {
    constructor(props) {
        super(props);
        this.age = 26
    }

    render() {
        return (
            <div>明年个人年龄是:{this.age + 1} 岁</div>
        );
    }
}

export default Demo;

效果一致:

clipboard.png

逻辑判断

书写React组件的时候没法使用if...else相关判断, 只能使用三元运算。举个例子,咱们实际开发中可使用某个变量进行判断而渲染出不一样的内容,好比:

import React, {Component} from 'react';

class Demo extends Component {
    constructor(props) {
        super(props);
        this.age = 18
    }

    render() {
        return (
            <div>
                {(this.age >= 18) ? <p>成年了</p> : <p>未成年</p>}
            </div>
        );
    }
}

export default Demo;

当年龄大于等于18岁的时候,就渲染出:
clipboard.png

若是小于18岁的话,就渲染出:
clipboard.png

注:这种写法在实际开发中常常用到,多多注意

样式处理

在React中添加样式和常规HTML+CSS开发是同样的,可使用行内样式也可使用class(React中是className)添加样式。这里主要介绍行内样式的处理,由于使用className处理样式又涉及到另外的技术了,有兴趣的朋友可了解下css module
JSX语法写样式和日常咱们写HTML行内样式大同小异,到底异在哪儿?咱们平时写HTML样式是这样写的:

<div style="background:red"></div>

就是给DOM元素添加style属性, 而后用分号分开的样式组成的字符串进行赋值,其实JSX的写法相似,只是赋值的不是字符串而是一个对象:

<div style={{"background":"red"}}></div>

修改下刚才的例子

import React, {Component} from 'react';

class Demo extends Component {
    constructor(props) {
        super(props);
        this.age = 17
    }

    render() {
        return (
            <div>
                {(this.age >= 18) ? <div style={{'background': 'red'}}>成年了</div> : <div style={{'background': 'red'}}>未成年</div>}
            </div>
        );
    }
}

export default Demo;

结果显示

clipboard.png

可能会有疑问为何是对象?虽然是React的规定,可是笔者认为JSX本质也是JavaScript, 编译器去编译JSX代码时候读取一个对象远比分析一段字符串要来得快。哈哈。。。一方之言,看看就好。固然,若是样式对象有多个该肿么办?很简单,使用ES6的解构,举个例子:

import React, {Component} from 'react';

class Demo extends Component {
    constructor(props) {
        super(props);
        this.age = 17
    }

    render() {
        const style1 = {'background': 'red'};
        const style2 = {'color': 'yellow'};
        return (
            <div>
                {(this.age >= 18) ? <div style={{...style1, ...style2}}>成年了</div> : <div style={{...style1, ...style2}}>未成年</div>}
            </div>
        );
    }
}

export default Demo;

这样样式正常显示

clipboard.png

批量渲染

最后来讲一下批量渲染。什么意思呢?假如咱们要从一个数据里取出数据而且渲染成一条一条的菜单项或者列表项,该如何作?前面说过,能够在组件的{}中写逻辑处理。最直接的方法以下:

import React, {Component} from 'react';

class Demo extends Component {
    constructor(props) {
        super(props);
        this.list = ['one', 'two', 'three']
    }

    render() {
        return (
            <ul>
                {
                    this.list.map(function (item) {
                        return (
                            <li>{item}</li>
                        )
                    })
                }
            </ul>
        );
    }
}

export default Demo;

clipboard.png

这样写能够实现需求,可是有个问题是组件代码结构复杂且冗余、维护代价高,尤为是当须要渲染的项目有别的复杂的需求的话,那么此处的复杂度就没法预计了,所以最有效最可靠的办法就是将生成项目的逻辑单独写在一个方法里并把项目放入数组中返回,能够这样写:

import React, {Component} from 'react';

class Demo extends Component {
    constructor(props) {
        super(props);
        this.list = ['one', 'two', 'three']
    }

    createList = (listData) => {
        return listData.map(function (item) {
            return (
                <li key={item}>{item}</li>
            )
        });
    };

    render() {
        const lists = this.createList(this.list);
        return (
            <ul>{lists}</ul>
        );
    }
}

export default Demo;

这样无论须要渲染的项有多复杂,只须要关注那个方法便可。不过有两点须要注意:

1 组件中自定义的方法建议必须使用ES6的箭头函数,由于它能保证this的正确指向。
2 在组件同一个节点渲染多个相同结构项目的时候请记得加上 key,而且值须要是对于 它们(这几个项目)而言都是独一无二的。有利于优化。

事件绑定

最后一个重头戏了。前端开发中给DOM绑定事件的动做处处都是。虽然说React对开发者和用户屏蔽了DOM但也提供了绑定事件的接口,幸运的是它和普通DOM事件绑定大同小异,异在哪儿?请参考样式绑定。。。哈哈
平时咱们给DOM绑定事件很简单

<div onClick='function'></div>

这样就实现了事件的绑定。React给组件的某个节点绑定事件也是如此:

import React, {Component} from 'react';

class Demo extends Component {
    constructor(props) {
        super(props);
    }

    handler = () => {
        alert('Click!')
    };

    render() {
        return (
            <div onClick={this.handler}>
                点我
            </div>
        );
    }
}

export default Demo;

演示结果

clipboard.png

之因此onClick后面是{}是由于须要从组件的this对象中取出该方法对象进行赋值。同时,咱们在组件中定义的方法都在this对象中

好了,差很少JSX的介绍就结束了, 平常开发经常使用的东西都在这里了(仅限笔者平常开发哇!)。其实若是要把JSX讲解清楚,这种篇幅的文章根本不够用。因此须要的是咱们在实际开发中不断得摸索和研究,实践方能出真知。另外若是你们须要实际操做的话, 能够将笔者已经搭建好的项目download下来,代码可自行修改,经过npm start运行便可。

相关文章
相关标签/搜索