[ 一塊兒學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運行便可。

相關文章
相關標籤/搜索