一段人人都應(yīng)該知道的從Vue到React的過渡史

寫在前面

以前寫Vue寫慣了浊闪,心血來潮,寫起了React概荷。并根據(jù)Vue官網(wǎng)文檔的語法順序秕岛,寫了對(duì)應(yīng)的React的語法,并附一個(gè)教程demo误证。

教程的github地址:Close2React

項(xiàng)目使用框架版本主要有 react(15.4.1) + react-dom(15.4.1) + webpack(1.13.3) + axios(0.15.3) + node(6.2.2), 詳情具體可見下文的【環(huán)境配置】

目前該項(xiàng)目有兩個(gè)分支, half-es6 + master

half-es6和master實(shí)現(xiàn)的功能一樣, 實(shí)現(xiàn)了CURD + Axios + Others

half-es6的寫法并沒有完全使用es6的class的概念, master是完善了它

環(huán)境配置

寫react就需要先配置webpack還有jsx

首先继薛,新建一個(gè)項(xiàng)目,npm init

然后在package中加入下面這些依賴

  "dependencies": {
    "react": "^15.4.1",
    "react-dom": "^15.4.1",
  },
  "devDependencies": {
    "axios": "^0.15.3",
    "babel-core": "^6.18.2",
    "babel-loader": "^6.2.8",
    "babel-preset-es2015": "^6.18.0",
    "babel-preset-react": "^6.16.0",
    "babel-preset-react-hmre": "^1.1.1",
    "bootstrap": "^4.0.0-alpha.2",
    "css-loader": "^0.26.1",
    "file-loader": "^0.9.0",
    "html-webpack-plugin": "^2.24.1",
    "node-sass": "^3.13.0",
    "open-browser-webpack-plugin": "0.0.3",
    "sass-loader": "^4.0.2",
    "style-loader": "^0.13.1",
    "url-loader": "^0.5.7",
    "webpack": "^1.13.3",
    "webpack-dev-server": "^1.16.2"
  }

有兩個(gè)比較重要的指令

  "scripts": {
    "dev": "webpack-dev-server --progress --profile --hot",
    "build": "webpack --progress --profile --colors"
  },

webpack.config

在webpack的配置中雷厂,我想要的目錄結(jié)構(gòu)是橫向目錄(自創(chuàng)詞 ???惋增,即所有index頁面要用到的東西,包括sass和js都寫在index目錄下,底下會(huì)有目錄示意圖)改鲫,目的是達(dá)到诈皿,我在src下編輯我想要的文件林束,打包后生成到public下去。
寫在配置最前面的是路徑的配置

var ROOT_PATH = path.resolve(__dirname);
var SRC_PATH = path.resolve(ROOT_PATH, 'src');
var PUBLIC_PATH = path.resolve(ROOT_PATH, 'Public');

配合著入口文件和輸出文件的配置

entry: {
    index: path.resolve(SRC_PATH, 'index/index.js'),
},
output: {
    path: PUBLIC_PATH,
    filename: '[name].bundle.js',
},

主要的插件就是這個(gè)html生成的插件和自動(dòng)打開瀏覽器的插件稽亏,還有babel的配置壶冒,不管三七二十一都把他們的等級(jí)開到最大

plugins: [
    new HtmlwebpackPlugin({
        title: 'My first react-webpack'
    }),
    new OpenBrowserPlugin({
        url: 'http://localhost:8200'
    })
],
babel: { //配置babel
    "presets": ["es2015",'stage-0', 'react'],
},

npm run dev,會(huì)自動(dòng)打開localhost:8200,就可以在瀏覽器上看到初始化的頁面

jsx

當(dāng)你開始要寫js的時(shí)候發(fā)現(xiàn)截歉,怎么這么多警告胖腾,

不用擔(dān)心 google 一下都能解決。

在這里下載react 和 react-native:


并勾選對(duì)應(yīng)項(xiàng)瘪松,保存:


警告會(huì)少很多咸作,但是還是有一些警告,怎么辦呢

點(diǎn)擊這個(gè)小燈泡宵睦,然后選擇configure


把這兩項(xiàng)勾選掉记罚,保存,就一片清凈了壳嚎。

項(xiàng)目描述

Public是打包后生成的目錄桐智,src是寫目錄

src采用橫向目錄結(jié)構(gòu)(自創(chuàng)詞 ???),即所有index頁面要用到的東西烟馅,包括sass和js都寫在index目錄下说庭。

指令運(yùn)行項(xiàng)目

npm i

npm run build 生成打包后的文件

npm run dev

數(shù)據(jù)綁定

1 文本插值

<span>{text}</span>

2 html 插值

<div dangerouslySetInnerHTML={{__html: "<p>balabalabalabala.......</p>"}} />

3 屬性賦值

<span id = {this.props.idName}></span>

<span className = "nav-box"></span>

4 帶js表達(dá)式的插值 xxx = {三元表達(dá)式}

<span className={this.props.idx == this.props.choice? "tab on" : "tab"} ></span>

5 事件綁定

事件綁定和屬性綁定一樣

// 如果沒有使用class繼承的寫法的話
getInitialState() {
    return {
        tabTxt: ['CURD', 'Axios', 'Others'],
        choice: 0,
    }
},
    
switchChoice(idx){
        this.setState({
            choice: idx
        })
    },
    
renderTabInit(text, idx) {
    return (<Tab key={idx} idx={idx}
             choose={this.switchChoice} // 綁定了switchChoice方法
             choice={this.state.choice} // 數(shù)據(jù)data的綁定,this.state可以獲取到整個(gè)state 
            >{text}</Tab>)
},

有可能會(huì)遇到一些BOOM爆炸的bug郑趁,請(qǐng)看react父子組件間的事件綁定

css和style的綁定

1 className

className={this.props.idx == this.props.choice? "tab on" : "tab"}

2 style

第一個(gè)括號(hào)是插值刊驴,第二個(gè)括號(hào)表示style對(duì)象

style={{color: '#FEC264', fontSize: '40px'}}


列表渲染 & 條件渲染

在getInitalState中定義了一個(gè)數(shù)組tabTxt

getInitialState() {
        return {
            tabTxt: ['CURD', 'Axios', 'Others'],
            choice: 0,
        }
    },

循環(huán)渲染這個(gè)子組件,每個(gè)子組件有自己的唯一的key穿撮,作用和track-by(或v-bind:key)的作用類似

renderTabInit(text, idx) {
        return (<Tab key={idx} idx={idx}
                     choose={this.switchChoice}
                     choice={this.state.choice}
        >{text}</Tab>)
    },

列表渲染的v-for 在react中使用map

v-if 的條件渲染可用三元缺脉,如復(fù)雜判斷則需要在return前寫邏輯代碼

render() {
    let currentPage = null;
    if(this.state.choice == 0) {
        currentPage = <PageA />
    } else if (this.state.choice == 1){
        currentPage = <PageB />
    } else {
        currentPage = <PageC />
    }
    return (
        <div id="content">
            <div id="navBox">
                {this.state.tabTxt.map(this.renderTabInit)}
            </div>
            <div id="pageBox">
                {currentPage}
            </div>
        </div>
    )
}

表單控件

表單組件有幾個(gè)受用戶影響的屬性:

value,用于input悦穿、textarea組件

checked, 用于類型為 checkbox 或者 radio 的 input 組件

selected业踢,用于option組件

每個(gè)表單控件都有一個(gè)onChange事件用來監(jiān)聽組件的變化:

當(dāng) input 或 textarea 的value 發(fā)生變化時(shí)

input 的 checked 狀態(tài)改變時(shí)

option 的 selected 狀態(tài)改變時(shí)

受限組件:

    //es5
    render: function() {
        return <input type="text" value="Hello!" />;
     }
    // 在渲染出來的元素里輸入任何值都不起作用栗柒,因?yàn)?React 已經(jīng)賦值為 Hello!

如果要讓用戶修改的值有用,則需要:

  getInitialState() {
    return {value: 'Hello!'};
  },
  handleChange(event) {
    this.setState({value: event.target.value});
  },
  render() {
    let value = this.state.value;
    return <input type="text" value={value} onChange={this.handleChange} />;
  }

不受限組件:

    //es5
   render: function() {
      return (
          <div>
            <input type="radio" name="opt" defaultChecked /> Option 1
            <input type="radio" name="opt" /> Option 2
            <select defaultValue="C">
              <option value="A">Apple</option>
              <option value="B">Banana</option>
              <option value="C">Cranberry</option>
            </select>
          </div>
      );
    }    
    // 用戶輸入將立即反應(yīng)到元素上知举。
    // 和受限元素一樣瞬沦,使用 onChange 事件可以監(jiān)聽值的變化。
    // default 有一個(gè)初始值雇锡,但這個(gè)值用戶可以改變并會(huì)反應(yīng)到界面上逛钻。  

父子組件通信

父子組件通信

// 父組件,相當(dāng)于最大的組件
// 子組件是一個(gè)tab锰提,和三個(gè)page曙痘,切換tab 就能切換 page
const Content = React.createClass({
    getInitialState() {
        return {
            tabTxt: ['CURD', 'Axios', 'Others'],
            choice: 0, // 當(dāng)前選中的tab下標(biāo)
        }
    },
    
    switchChoice(idx){
        this.setState({ // 修改state    
            choice: idx
        })
    },
    
    renderTabInit(text, idx) {
        return (<Tab key={idx} idx={idx}
                 choice={this.state.choice}  // key\idx\choice 分別都是作為props傳入tab子組件的參數(shù)名
                 choose={this.switchChoice}  // choose 作為props作為傳入tab子組件的方法名
              >{text}</Tab>)
    },
    
    render() {
        let currentPage = null;
        if(this.state.choice == 0) { // 條件判斷
            currentPage = <PageA />
        } else if (this.state.choice == 1){
            currentPage = <PageB />
        } else {
            currentPage = <PageC />
        }
        return (
            <div id="content">
                <div id="navBox">
                    {this.state.tabTxt.map(this.renderTabInit)} //循環(huán)輸出
                </div>
                <div id="pageBox">
                    {currentPage}
                </div>
            </div>
        )
    }
});

在使用事件綁定choose={this.switchChoice} 的時(shí)候芳悲,因?yàn)闆]有采用class的學(xué)法所以不用bind

class的寫法的時(shí)候需要bind: choose={this.switchChoice.bind(this)}

不用class的寫法的時(shí)候不綁定不會(huì)導(dǎo)致子組件的this指向錯(cuò)誤,如果綁定了還會(huì)報(bào)錯(cuò)(如綁定this會(huì)有警告)

使用了class的寫法的時(shí)候則需要手動(dòng)bind, 這個(gè)在文章最后會(huì)詳細(xì)解說

// tab 子組件
const Tab = React.createClass({
    chooseTab() {
        this.props.choose(this.props.idx); //一定要將父組件的方法在子組件中做一個(gè)中轉(zhuǎn)
    },
    
    render(){
        return (
            <span className={this.props.idx == this.props.choice? "tab on" : "tab"}
                  style={{color: '#FEC264', fontSize: '40px'}}
                  data-idx={this.props.idx}
                  onClick={this.chooseTab} // 調(diào)用子組件的方法
            >{this.props.children}</span>
        )
    }
});

獲取dom元素

當(dāng)你的組件還沒有掛載在容器上边坤,可以用this.refs訪問

已經(jīng)掛載完畢名扛,通過react-dom提供findDOMNode方法拿到組件對(duì)應(yīng)的dom

另外:

如果ref是設(shè)置在原生HTML元素上,它拿到的就是DOM元素;

如果設(shè)置在自定義組件上茧痒,它拿到的就是組件實(shí)例肮韧,這時(shí)候就需要通過 findDOMNode來拿到組件的DOM元素。

//es5
var MyComponent = React.createClass({
  handleClick: function() {
    this.refs.myTextInput.getDOMNode().focus(); // 通過this.refs.xxxxx拿到元素
  },
  render: function() {
    return (
      <div>
        <input type="text" ref="myTextInput" /> // 給輸入框命名ref 
        <input
          type="button"
          value="Focus the text input"
          onClick={this.handleClick}
        />
      </div>
    );
  }
});

幾個(gè)常用api

componentDidMount

componentWillReceiveProps(nextProps)


花一分鐘,改成正統(tǒng)的class寫法

第一步旺订,把所有createClass 換成 class xxx extends Component

我們用一半的es6的姿勢(shì)寫出來的代碼如下:

// half-es6
import React from 'react';
const List = React.createClass({ // 用createdClass創(chuàng)建一個(gè)組件
    getInitialState() { // 初始化數(shù)據(jù)state    
        return { // 在函數(shù)的return里定義state
            status: false, 
        }
    }, // 這里一定寫逗號(hào)
    saveLiValue() { // 組件內(nèi)要調(diào)用的function
        this.setState({
            status: false
        })
    },
    ....
})

我們用完整的es6的姿勢(shì)寫出來的代碼如下:

// master
// 利用class姿勢(shì)的es6
import React, {Component} from 'react';
class List extends Component{
    constructor(props){
        super(props);
        this.state = { 
            status: false, 
        }
    } // 沒有逗號(hào)
    
    saveLiValue() {
        this.setState({
            status: false
        })
    }
    ....
}   

第二步弄企,在父組件中,給所有需要傳遞給子組件的方法加bind(this)

這句話有點(diǎn)繞口区拳,但一定要理解桩蓉。

1、第一層意思是在父組件上加bind(this)

2劳闹、加的目的是防止子組件在調(diào)用方法的時(shí)候this指向錯(cuò)誤

例如下面這個(gè)初始化列表的函數(shù)

// half-es6
// 如果在這種寫法下bind(this)院究,編譯后的頁面會(huì)報(bào)警告
// 大概是說react已經(jīng)提供了豐富的方法可以避免指向錯(cuò)誤,不需要手動(dòng)bind
initListLi(val, idx) {
    return (
        <List {...val} key={idx} index={idx}
              handleTxtChange={this.handleTxtChange}
              handleCheckChange={this.handleCheckChange}
              deleteItem={this.deleteItem}
        />
    )
},

render() {
    return (
        <article className="page">
            <h3 className="h3">List總條數(shù): {this.state.list.length}</h3>
            <h3 className="h3">目前完成條數(shù): {this.state.didCount}</h3>
            <ul className="ul">
                {
                    this.state.list.map(this.initListLi)
                }
            </ul>
            <Add addLiItem={this.addLiItem}/>
        </article>
    )
}

但是使用了class的寫法之后本涕,就可能會(huì)出現(xiàn)警告說 props 是null

這個(gè)時(shí)候就需要手動(dòng)bind(this)

// master
// es6的class寫法下的函數(shù)的事件綁定业汰,
// 如果子組件會(huì)需要調(diào)用函數(shù),則在父組件中手動(dòng)向子組件中bind(this)
initListLi(val, idx) {
    return (
        <List {...val} key={idx} index={idx}
              // 以下三個(gè)方法都是在向List組件中綁定this
              handleTxtChange={this.handleTxtChange.bind(this)} 
              handleCheckChange={this.handleCheckChange.bind(this)}
              deleteItem={this.deleteItem.bind(this)}
        />
    )
}

render() {
    return (
        <article className="page">
            <h3 className="h3">List總條數(shù): {this.state.list.length}</h3>
            <h3 className="h3">目前完成條數(shù): {this.state.didCount}</h3>
            <ul className="ul">
                {
                    this.state.list.map(this.initListLi.bind(this)) //子組件中會(huì)需要調(diào)用函數(shù)
                }
            </ul>
            <Add addLiItem={this.addLiItem.bind(this)}/>
        </article>
    )
}

寫在后面

github地址:Close2React

我是嘉寶Appian菩颖,一個(gè)賣萌出家的算法妹紙样漆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市晦闰,隨后出現(xiàn)的幾起案子放祟,更是在濱河造成了極大的恐慌,老刑警劉巖呻右,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跪妥,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡声滥,警方通過查閱死者的電腦和手機(jī)眉撵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來落塑,“玉大人纽疟,你說我怎么就攤上這事『读蓿” “怎么了污朽?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長龙考。 經(jīng)常有香客問我蟆肆,道長矾睦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任颓芭,我火速辦了婚禮顷锰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘亡问。我一直安慰自己官紫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布州藕。 她就那樣靜靜地躺著束世,像睡著了一般。 火紅的嫁衣襯著肌膚如雪床玻。 梳的紋絲不亂的頭發(fā)上毁涉,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天,我揣著相機(jī)與錄音锈死,去河邊找鬼贫堰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛待牵,可吹牛的內(nèi)容都是我干的其屏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼缨该,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼偎行!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起贰拿,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤蛤袒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后膨更,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妙真,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年询一,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了箕般。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒂秘。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绪抛,死狀恐怖柔滔,靈堂內(nèi)的尸體忽然破棺而出贫母,到底是詐尸還是另有隱情但金,我是刑警寧澤夕膀,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布箫章,位于F島的核電站都办,受9級(jí)特大地震影響嫡锌,放射性物質(zhì)發(fā)生泄漏虑稼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一势木、第九天 我趴在偏房一處隱蔽的房頂上張望蛛倦。 院中可真熱鬧,春花似錦啦桌、人聲如沸溯壶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽且改。三九已至,卻和暖如春板驳,著一層夾襖步出監(jiān)牢的瞬間又跛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來泰國打工若治, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留慨蓝,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓端幼,卻偏偏與公主長得像礼烈,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子静暂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

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

  • 深入JSX date:20170412筆記原文其實(shí)JSX是React.createElement(componen...
    gaoer1938閱讀 8,065評(píng)論 2 35
  • 本筆記基于React官方文檔济丘,當(dāng)前React版本號(hào)為15.4.0。 1. 安裝 1.1 嘗試 開始之前可以先去co...
    Awey閱讀 7,706評(píng)論 14 128
  • 以下內(nèi)容是我在學(xué)習(xí)和研究React時(shí)洽蛀,對(duì)React的特性摹迷、重點(diǎn)和注意事項(xiàng)的提取、精練和總結(jié)郊供,可以做為React特性...
    科研者閱讀 8,232評(píng)論 2 21
  • 目前峡碉,react組件有三種寫法,分別是es5的createClass寫法驮审,es6的class寫法鲫寄,以及statel...
    ZoomFunc閱讀 1,654評(píng)論 0 1
  • 他們處于不同的時(shí)空之中。只是在那么一兩個(gè)點(diǎn)中疯淫,有了些許的相交地来。而舒禾,把這作為自己生活里熙掺,可以想象的美好未斑。自己給自...
    沐茶小野公舉SUNNY閱讀 252評(píng)論 2 0