React 基礎(chǔ)知識介紹

React 基礎(chǔ)知識介紹

本章節(jié)會介紹一些 React 的基礎(chǔ)知識和基本用法。已經(jīng)入門 React 基礎(chǔ)的同學(xué)坡椒,可以簡單看看這篇文檔并略過視頻內(nèi)容扰路。React 零基礎(chǔ)的同學(xué)還建議去慕課網(wǎng)學(xué)習(xí)React入門基礎(chǔ)

另外倔叼,本教程的代碼將全部使用 es6 語法汗唱,教程中我會介紹一些用到的 es6 語法,但是不會從頭講解了丈攒,推薦閱讀es6入門

hello world

以下是一個最簡單的demo哩罪,將一個最簡單的組件渲染到頁面上。

import React from 'react'
import { render } from 'react-dom'

// 定義組件
class Hello extends React.Component {
    render() {
        // return 里面寫jsx語法
        return (
            <p>hello world</p>
        )
    }
}

// 渲染組件到頁面
render(
    <Hello/>,
    document.getElementById('root')
)

深入一下巡验,這里import React from 'react'引用的是什么际插?

這里的'react'對應(yīng)的就是./package.json文件中dependencies中的'react',即在該目錄下用npm install安裝的 react 显设。npm 安裝的 react 的物理文件是存放在 ./node_modules/react中的框弛,因此引用的東西肯定就在這個文件夾里面。

打開./node_modules/react/package.json找到"main": "react.js",捕捂,這里的main即指定了入口文件功咒,即./node_modules/react/react.js這個文件。那么绞蹦,問題的答案自然就出來了。

jsx 語法

React 里面寫模板要使用 jsx 語法榜旦,它其實和 html 很相似但是又有那么幾點不一樣幽七。下面簡單介紹一下 jsx 語法的一些特點:

使用一個父節(jié)點包裹

jsx 中不能一次性返回零散的多個節(jié)點,如果有多個請包涵在一個節(jié)點中溅呢。例如澡屡,

// 三個 <p> 外面必須再包裹一層 <div>
return (
  <div>
    <p>段落1</p>
    <p>段落2</p>
    <p>段落3</p>
  </div>
)

再例如:

// { } 中返回的兩個 <p> 也要用 <div> 包裹
return (
  <div>
    <p>段落1</p>
    {
      true 
      ? <p>true</p>
      : <div>
        <p>false 1</p>
        <p>false 2</p>
      </div>
    }
  </div>
)

注釋

jsx 中用{/* */}的注釋形式

        return (
            // jsx 外面的注釋
            <div>
                {/* jsx 里面的注釋 */}
                <p>hello world</p>
            </div>
        )

樣式

對應(yīng) html 的兩種形式,jsx 的樣式可以這樣寫:
css樣式:<p className="class1">hello world</p>咐旧,注意這里是className驶鹉,而 html 中是class
內(nèi)聯(lián)樣式:<p style={{display: 'block', fontSize: '20px'}}>hello world</p>,注意這里的{{...}}铣墨,還有fontSize的駝峰式寫法

事件

拿 click 事件為例室埋,要在標(biāo)簽上綁定 click 事件,可以這樣寫

class Hello extends React.Component {
    render() {
        return (
            <p onClick={this.clickHandler.bind(this)}>hello world</p>
        )
    }

    clickHandler(e) {
        // e 即js中的事件對象伊约,例如 e.preventDefault()
        // 函數(shù)執(zhí)行時 this 即組件本身姚淆,因為上面的 .bind(this)
        console.log(Date.now())
    }
}

注意,onClick是駝峰式寫法屡律,以及.bind(this)的作用

循環(huán)

在 jsx 中使用循環(huán)腌逢,一般會用到Array.prototype.map(來自ES5標(biāo)準)

class Hello extends React.Component {
    render() {
        const arr = ['a', 'b', 'c']
        return (
            <div>
                {arr.map((item, index) => {
                    return <p key={index}>this is {item}</p>
                })}
            </div>
        )
    }
}

注意,arr.map是包裹在{}中的超埋,key={index}有助于React的渲染優(yōu)化搏讶,jsx中的{}可放一個可執(zhí)行的 js 程序或者變量

判斷

jsx中使用判斷一般會用到三元表達式(表達式也是放在{}中的)佳鳖,例如:

return (
  <div>
    <p>段落1</p>
    {
      true 
      ? <p>true</p>
      : <p>false</p>
      </div>
    }
  </div>
)

也可以這樣使用:

<p style={{display: true ? 'block' ? 'none'}}>hello world</p>

代碼分離

之前的demo代碼都是在一個文件中,實際開發(fā)中不可能是這樣子的媒惕,因此這里就先把組件的代碼給拆分開系吩。我們將使用 es6 的模塊管理規(guī)范。

page 層

創(chuàng)建./app/containers/Hello/index.jsx文件吓笙,將之前創(chuàng)建組件代碼復(fù)制進去

import React from 'react'

class Hello extends React.Component {
    render() {
        return (
             <p>hello world</p>
        )
    }
}

export default Hello

然后./app/index.jsx中代碼就可以這樣寫淑玫。

import Hello from './containers/Hello';

render(
    <Hello/>,
    document.getElementById('root')
)

注意,代碼import Hello from './containers/Hello';這里可以寫成./containers/Hello/index.jsx也可以寫成./containers/Hello/index

subpage 層

如果Hello組件再稍微復(fù)雜一點面睛,那么把代碼都放一塊也會變得復(fù)雜絮蒿,接下來我們再拆分。

創(chuàng)建./app/containers/Hello/subpage目錄叁鉴,然后在其下創(chuàng)建三個文件Carousel.jsx Recommend.jsx List.jsx土涝,分別寫入相應(yīng)的代碼(看代碼文件即可),然后./app/containers/Hello/index.js中即可這樣寫

import Carousel from './subpage/Carousel'
import Recommend from './subpage/Recommend'
import List from './subpage/List'

class Hello extends React.Component {
    render() {
        return (
            <div>
                <p>hello world</p>
                <hr/>
                <Carousel/>
                <Recommend/>
                <List/>
            </div>
        )
    }
}

注意幌墓,這里import.jsx后綴省略了但壮。

component 層

以上介紹的是頁面和復(fù)雜頁面的拆分,但那都是頁面層級的常侣,即page層蜡饵。這里復(fù)雜頁面拆分為subpage其實沒啥特別的,就是把復(fù)雜頁面的代碼拆分一下胳施,會更加符合開放封閉原則溯祸。而且,只有復(fù)雜頁面才有必要去拆分舞肆,簡單頁面根本沒必要拆分焦辅。因此,無論是page還是subpage它都是頁面級別的椿胯。

頁面的特點是其獨特性筷登,一個頁面就需要創(chuàng)建一個文件(如果兩個頁面可以共用一個文件,這是設(shè)計不合理哩盲,得治)前方。而頁面其中的內(nèi)容,就不一定是這樣子了廉油。例如镣丑,現(xiàn)在的APP每個頁面最上面都會有個 header ,即可以顯示標(biāo)題娱两,可以返回莺匠。每個頁面都有,樣子差不多十兢,難道我們要為每個頁面都做一個趣竣?——當(dāng)然不是摇庙。

創(chuàng)建./app/components/Header/index.jsx文件,簡單寫入一個組件的代碼(見源碼文件)遥缕,然后在./app/containers/index.jsx中引用

import Header from '../../components/Header'

class Hello extends React.Component {
    render() {
        return (
            <div>
                <Header/>
                {/* 省略其他內(nèi)容 */}
            </div>
        )
    }
}

Hello 頁面會用到 Header卫袒,以后的其他頁面也會用到 Header ,我們把多個頁面都可能用到的功能单匣,封裝到一個組件中夕凝,代碼放在./app/components下。

數(shù)據(jù)傳遞 & 數(shù)據(jù)變化

props

接著剛才 Header 的話題往下說户秤,每個頁面都會使用 Header 码秉,但是 Header 上顯示的標(biāo)題每個頁面肯定是不一樣的。我們需要這樣解決:頁面中引用Header時鸡号,這樣寫 <Header title="Hello頁面"/>转砖,即給 Header 組件設(shè)置一個 title 屬性。而在 Header 組件中可以這樣取到

    render() {
        return (
             <p>{this.props.title}</p>
        )
    }

在 React 中鲸伴,父組件給子組件傳遞數(shù)據(jù)時府蔗,就是以上方式,通過給子組件設(shè)置 props 的方式汞窗,子組件取得 props 中的值即可完成數(shù)據(jù)傳遞姓赤。被傳遞數(shù)據(jù)的格式可以是任何 js 可識別的數(shù)據(jù)結(jié)構(gòu),上面demo是一個字符串仲吏。React 中模捂,props 一般只作為父組件給子組件傳遞數(shù)據(jù)用,不要試圖去修改自己的 props 蜘矢,除非你想自找麻煩

props && state

上面提到了 props 不能被自身修改,如果組件內(nèi)部自身的屬性發(fā)生變化综看,該怎么辦品腹?—— React 為我們提供給了 state,先看一個demo:

class Hello extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.state = {
            // 顯示當(dāng)前時間
            now: Date.now()
        }
    }
    render() {
        return (
            <div>
                <p>hello world {this.state.now}</p>
            </div>
        )
    }
}

還有一點非常重要红碑,React 會實時監(jiān)聽每個組件的 props 和 state 的值舞吭,一旦有變化,會立刻更新組件析珊,將結(jié)果重新渲染到頁面上羡鸥,下面demo演示了state的變化,props也是一樣的

class Hello extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.state = {
            // 顯示當(dāng)前時間
            now: Date.now()
        }
    }
    render() {
        return (
            <div>
                <p onClick={this.clickHandler.bind(this)}>hello world {this.state.now}</p>
            </div>
        )
    }
    clickHandler() {
        // 設(shè)置 state 的值的時候忠寻,一定要用 this.setState 惧浴,不能直接賦值修改
        this.setState({
            now: Date.now()
        })
    }
}

智能組件 & 木偶組件

這是用 React 做系統(tǒng)設(shè)計時的兩個非常重要的概念。雖然在 React 中奕剃,所有的單位都叫做“組件”衷旅,但是通過以上例子捐腿,我們還是將它們分別放在了./app/containers./app/components兩個文件夾中。為何要分開呢柿顶?

  • 智能組件 在日常開發(fā)中茄袖,我們也簡稱“頁面”。為何說它“智能”嘁锯,因為它只會做一些很聰明的事兒宪祥,臟活累活都不干。它只對數(shù)據(jù)負責(zé)家乘,只需要獲取了數(shù)據(jù)蝗羊、定義好數(shù)據(jù)操作的相關(guān)函數(shù),然后將這些數(shù)據(jù)烤低、函數(shù)直接傳遞給具體實現(xiàn)的組件即可肘交。
  • 木偶組件 這里“木偶”一詞用的特別形象,它總是被人拿線牽著扑馁。它從智能組件(或頁面)那里接受到數(shù)據(jù)涯呻、函數(shù),然后就開始做一些展示工作腻要,它的工作就是把拿到的數(shù)據(jù)展示給用戶复罐,函數(shù)操作開放給用戶。至于數(shù)據(jù)內(nèi)容是什么雄家,函數(shù)操作是什么效诅,它不關(guān)心。

以上兩個如果不是理解的很深刻趟济,待把課程學(xué)完再回頭看一下這兩句話乱投,相信會理解的。

生命周期

React 詳細的生命周期可參見這里顷编,也可查閱本文檔一開始的視頻教程戚炫。這里我們重點介紹這個項目開發(fā)中常用的幾個生命周期函數(shù)(hook),相信你在接下來的 React 開發(fā)中媳纬,也會常用這些双肤。

以下聲明周期,也沒必要每個都寫demo來解釋钮惠,先簡單了解一下茅糜,后面會根據(jù)實際的例子來解釋,這樣會更加易懂素挽。

  • getInitialState

初始化組件 state 數(shù)據(jù)蔑赘,但是在 es6 的語法中,我們可以使用以下書寫方式代替

class Hello extends React.Component {
    constructor(props, context) {
        super(props, context);
        // 初始化組件 state 數(shù)據(jù)
        this.state = {
            now: Date.now()
        }
    }
}
  • render

最常用的hook,返回組件要渲染的模板米死。

  • comopentDidMount

組件第一次加載時渲染完成的事件锌历,一般在此獲取網(wǎng)絡(luò)數(shù)據(jù)。實際開始項目開發(fā)時峦筒,會經(jīng)常用到晓褪。

  • shouldComponentUpdate

主要用于性能優(yōu)化芜繁,React 的性能優(yōu)化也是一個很重要的話題,后面一并講解。

  • componentDidUpdate

組件更新了之后觸發(fā)的事件哟玷,一般用于清空并更新數(shù)據(jù)茬底。實際開始項目開發(fā)時坯沪,會經(jīng)常用到筒严。

  • componentWillUnmount

組件在銷毀之前觸發(fā)的事件,一般用戶存儲一些特殊信息尉辑,以及清理setTimeout事件等帆精。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市隧魄,隨后出現(xiàn)的幾起案子卓练,更是在濱河造成了極大的恐慌,老刑警劉巖购啄,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件襟企,死亡現(xiàn)場離奇詭異,居然都是意外死亡狮含,警方通過查閱死者的電腦和手機顽悼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來几迄,“玉大人蔚龙,你說我怎么就攤上這事∮承玻” “怎么了木羹?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長屿愚。 經(jīng)常有香客問我,道長务荆,這世上最難降的妖魔是什么妆距? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮函匕,結(jié)果婚禮上娱据,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好中剩,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布忌穿。 她就那樣靜靜地躺著,像睡著了一般结啼。 火紅的嫁衣襯著肌膚如雪掠剑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天郊愧,我揣著相機與錄音朴译,去河邊找鬼。 笑死属铁,一個胖子當(dāng)著我的面吹牛眠寿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播焦蘑,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼盯拱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了例嘱?” 一聲冷哼從身側(cè)響起狡逢,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蝶防,沒想到半個月后甚侣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡间学,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年殷费,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片低葫。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡详羡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嘿悬,到底是詐尸還是另有隱情实柠,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布善涨,位于F島的核電站窒盐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏钢拧。R本人自食惡果不足惜蟹漓,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望源内。 院中可真熱鬧葡粒,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至夫壁,卻和暖如春拾枣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掌唾。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工放前, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人糯彬。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓凭语,卻偏偏與公主長得像,于是被迫代替她去往敵國和親撩扒。 傳聞我的和親對象是個殘疾皇子似扔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容