React

簡(jiǎn)介

當(dāng)2014年Facebook推出React時(shí),給整個(gè)業(yè)界帶來全新的看待網(wǎng)頁應(yīng)用開發(fā)的方式,和React一同問世的Flux,也克服傳統(tǒng)MVC框架的很多弊病嘱朽。技術(shù)在不斷發(fā)展软吐,在2015年瘩将,F(xiàn)lux的一個(gè)變體Redux出現(xiàn),進(jìn)一步優(yōu)化了Flux的功能。


優(yōu)秀之處:

? 專注視圖層:(不處理路由姿现,數(shù)據(jù)肠仪,以及邏輯的處理

? VirtualDom只對(duì)虛擬dom更新,不對(duì)真實(shí)dom更新备典;只對(duì)dom進(jìn)行必要的更新异旧,實(shí)現(xiàn)的重繪的最小化;

? jsx語法:

? 高內(nèi)聚提佣,低耦合

? onClick 不是原生dom中的onclick事件泽艘,這里是onClict是通過react的事件委托方式,觸發(fā)掛在頂層dom節(jié)點(diǎn)上的一個(gè)事件處理函數(shù)(提高了性能)镐依;

? 可以將樣式一起寫入組件文件中匹涮;

? 關(guān)于jsx語法的說法:

? 在jsx語法中可以直接寫入組件,注意組件為了和普通標(biāo)簽區(qū)別槐壳,必須第一個(gè)字母大寫然低;

? jsx語法是歷史的進(jìn)步還是倒退;(樣式务唐,結(jié)構(gòu)雳攘,邏輯于一體)

? 活躍的生態(tài)圈:(開源項(xiàng)目)

? 組件式開發(fā)

? 手動(dòng)搭建項(xiàng)目:

? npm init

? 安裝項(xiàng)目依賴

cnpm install --save-dev babel-core babel-loader babel-preset-stage-2 babel-plugin-transform-react-jsx babel-plugin-transform-runtime babel-preset-es2015 babel-preset-react babel-preset-stage-0 css-loader html-loader html-webpack-plugin react react-dom style-loader url-loader webpack webpack-dev-server

? 配置babelrc文件:

?{

????"presets": [

????????"es2015",

????????"stage-0",

????????"react"

????],

????"plugins": ["transform-runtime", "transform-react-jsx"]

}

? webpack.config.js的配置文件:

除了如下配置有更改,其他可以完全遵照vue的配置

{

????????????????test:?/\.js|.jsx$/,

????????????????use: [

????????????????????"babel-loader",

????????????????],

????????????????exclude:?/node_modules/

????????????},

? 在vsCode中開發(fā)react的配置:

安裝jsx插件配置如下:


安裝React/Redux/react-router Snippets插件枫笛,可以幫助我們快速生成一定的語句吨灭;

所有的react組件使用jsx后綴來標(biāo)識(shí);

? 自動(dòng)化構(gòu)建項(xiàng)目:

? 初始化:

全局安裝:

npm install –-global create- react- app

初始化項(xiàng)目:

create- react- app myReactApp

啟動(dòng)服務(wù):

cd myReactApp

npm start

? 組件寫法:


import?React,{Component}?from "react"

import?ClickCount?from "./ClickCount.jsx"

class?Main extends?Component {

??constructor(props){

????super(props)

??}

??render(){

????return?(

??????<ul>

????????<li><ClickCount?name="first"?num={1}></ClickCount></li>

????????<li><ClickCount?name="second"?num={10}></ClickCount></li>

????????<li><ClickCount?name="third"?num={7}></ClickCount></li>

??????</ul>

????)

??}

}

export default?Main

注:對(duì)于jsx語法的解析必須引入React刑巧,雖然這里不用喧兄,但是如果不引入會(huì)因無法解析jsx而報(bào)錯(cuò);組件的定義必須遵循首字母大寫

? jsx語法使用:

屬性:

1啊楚、屬性值直接為字符串

2吠冤、動(dòng)態(tài)解析屬性值

const?element =?(<img src={user.avatarUrl}></img>);

react的jsx:

const?element =?(

??<h1 className="greeting">

????Hello, world!

??</h1>

);


用React.createElement()同樣可以達(dá)到同樣的效果;

const?element =?React.createElement(

??'h1',

??{className:?'greeting'},

??'Hello, world!'

);

? 項(xiàng)目的分解:

npm run eject 進(jìn)行項(xiàng)目配置文件的彈射恭理;

? react的工作方式:

? 從繁瑣的dom處理中解脫出來拯辙,響應(yīng)式,函數(shù)式編程思維颜价;輸入相同的數(shù)據(jù)涯保,將產(chǎn)出相同的效果;數(shù)據(jù)更新周伦,dom同時(shí)做出更新夕春;

? Virtual Dom

Dom:結(jié)構(gòu)化文本的抽象表達(dá)式;

虛擬dom:對(duì)dom樹的抽象横辆,不會(huì)觸及瀏覽器撇他,只存在于js內(nèi)存的空間樹形結(jié)構(gòu),每次的數(shù)據(jù)刷新狈蚤,render函數(shù)的執(zhí)行都會(huì)觸發(fā)一個(gè)新舊虛擬dom 的對(duì)比困肩,如果無改變,則不更新脆侮,有改變锌畸,只更新相應(yīng)dom結(jié)構(gòu);

? 元素的渲染

? jsx語法將元素渲染到dom

? 更新元素渲染:

React 元素都是immutable 不可變的靖避。當(dāng)元素被創(chuàng)建之后潭枣,你是無法改變其內(nèi)容或?qū)傩缘模桓陆缑娴奈ㄒ环椒ň褪侵匦聮燧d節(jié)點(diǎn)

function?tick() {

??const element = (

??????<h2>{new?Date().toLocaleTimeString()}.</h2>

??);

??ReactDOM.render(

????element,

????document.getElementById('root')

??);

}

setInterval(tick, 1000);


? 只會(huì)更新必要的部分(可以在谷歌開發(fā)者工具中進(jìn)行dom更新的查看)

? reactjsx語法中幻捏,如果標(biāo)簽沒有子元素盆犁,可以直接使用閉合標(biāo)簽;

? react的組件必須首字母進(jìn)行大寫篡九,否則React.createEelement則無法查找到組件谐岁,進(jìn)行編譯;

? jsx支持標(biāo)簽名為表達(dá)式榛臼;伊佃,如果使用動(dòng)態(tài)標(biāo)簽名,則需先將表達(dá)式解析賦值給一個(gè)變量沛善;



? React組件以及基本語法:

? 組件的設(shè)計(jì)要素:

高內(nèi)聚:把邏輯緊密相關(guān)的內(nèi)容放在一個(gè)組件中航揉;

低耦合:不同組件之間的依賴關(guān)系要盡量弱化;盡量保持每個(gè)組件的獨(dú)立性金刁;

? 組件的生命周期:

? 裝載過程:

? Constructor:

初始化state帅涂;

綁定成員函數(shù)的this環(huán)境(bind、::?)防止以解構(gòu)的方式進(jìn)行全局作用域進(jìn)行調(diào)用尤蛮;

例:this.fn=this.fn.bind(this)或this.fn=::this.fn

? GetInitialState:初始化state值,必須結(jié)合React.createClass()使用漠秋,使用es6的方式,此函數(shù)無效果抵屿;


const Test=React.createClass({

??getInitialState:function(){

????return?{

??????name:"zhangsan"

????}

??},

??getDefaultProps:function(){

????return?{

??????name:"zhangsan"?//這里的zhangsan相當(dāng)于默認(rèn)值

????}

??}

})


? GetDefaultProps:初始化props值,必須結(jié)合React.createClass()使用庆锦,使用es6的方式茉继,此函數(shù)無效果携御,用屬性defaultProps代替;



class?Test extends?Component {

??constructor(props){

super(props)

this.state={data:new Date()}

??}

??render(){

????return?(

??????<ul>

????????<li><ClickCount?name="third"?num={7}></ClickCount></li>

??????</ul>

????)

??}

}

Test.defaultProps={

????name:"moren"

}



? ComponentWillMount:在render函數(shù)調(diào)用之前進(jìn)行調(diào)用臀蛛;

? Render:并不做實(shí)際的渲染動(dòng)作尿扯,只返回一個(gè)jsx描述結(jié)構(gòu)求晶,最后渲染與否由react來決定;必須是個(gè)純函數(shù)衷笋,不能設(shè)計(jì)到數(shù)據(jù)的更變(this.setState)芳杏;


render(){

????return?(

??????<ul>

????????<li><ClickCount?name="third"?num={7}></ClickCount></li>

??????</ul>

????)

??}


? ComponentDidMount :在render函數(shù)調(diào)用之后進(jìn)行調(diào)用;但不是在render函數(shù)調(diào)用之后立即調(diào)用,而是當(dāng)所有的dom樹掛載并渲染完成后才會(huì)調(diào)用爵赵,這是因?yàn)閞ender函數(shù)并不進(jìn)行渲染吝秕,而只是返回一個(gè)jsx對(duì)象,渲染的工作由react庫進(jìn)行空幻,只有當(dāng)所有的組件的jsx對(duì)象組合完畢之后烁峭,react通過對(duì)比后才會(huì)渲染,所有此鉤子函數(shù)是發(fā)生的所有組件的render函數(shù)都執(zhí)行后才會(huì)執(zhí)行秕铛;(只能在瀏覽器端觸發(fā))

注:與angular中的link或者post函數(shù)有點(diǎn)相似约郁,但是這里不僅指子組件,而是當(dāng)前組件中的所有組件但两,包括兄弟組件鬓梅;提供了dom操作的接口

? 更新過程:

? ComponentWillReceiveProps:傳入的props的改變或者組件進(jìn)行刷新(forceUpdate函數(shù)觸發(fā)組件的刷新)都會(huì)觸發(fā)此函數(shù),但是通過this.setState改變的數(shù)據(jù)則不會(huì)觸發(fā)此函數(shù)谨湘,

? ShouldComponentUpdate:react組件的鉤子函數(shù)兩個(gè)需要有返回值的鉤子函數(shù)之一己肮,另一個(gè)為render,此鉤子函數(shù)的返回值為一個(gè)bolen值悲关,如果為true時(shí)谎僻,則prop的改變以及state的改變都會(huì)引起組件的刷新,如果為false時(shí)寓辱,則不再進(jìn)行渲染艘绍;此鉤子函數(shù)接受兩個(gè)參數(shù),一個(gè)是nextProps秫筏,一個(gè)是nextState诱鞠,可以將將要更新的值和此時(shí)的做對(duì)比,然后返回true和false來進(jìn)行性能的校優(yōu)这敬;

? ComponentWillUpdate:跟componentWillMount相似

? Render

? ComponentDidUpdate:跟componentDidMount相似

? 卸載過程:

ComponentWillUnmount:此鉤子函數(shù)可以在組件卸載前執(zhí)行航夺,可以進(jìn)行手動(dòng)添加dom元素的刪除,以及計(jì)時(shí)器和事件監(jiān)聽的移除崔涂;

? React組件的數(shù)據(jù)

組件內(nèi)部數(shù)據(jù)類型:

兩種數(shù)據(jù)結(jié)構(gòu)阳掐,prop和state,這兩種數(shù)據(jù)的改變都會(huì)引起組件的重新渲染冷蚂;

? Prop:組件的外部接口缭保,接受外部數(shù)據(jù);跟html的屬性的書寫類似蝙茶,但是除了接受字符串之外艺骂,還可以接受js對(duì)象,數(shù)字等的隆夯;如果組件進(jìn)行數(shù)據(jù)反饋給外界钳恕,可以通過prop傳入組件一個(gè)函數(shù)别伏;

? Prop的讀取:

由class類的constructor函數(shù)接受忧额,以及super()方法調(diào)用時(shí)的傳入厘肮;

最后的props為一個(gè)對(duì)象,鍵值分別為傳入時(shí)的屬性名宙址;這里比較方便的是使用es6的解構(gòu)賦值轴脐;

? PropTypes的檢查:

可以通過增加類的propTypes屬性來定義prop規(guī)格调卑,在constructor函數(shù)中進(jìn)行如下定義:

Index.propTypes={ ????//組件全局進(jìn)行配置

caption:PropTypes.string.isRequired,

initValue:PropTypes.number

}

注意:此屬性不會(huì)影響組件的渲染抡砂,只是做到在開發(fā)過程中輔助開發(fā);

? State:由于組件不能改變出入的prop恬涧,所以當(dāng)組件要進(jìn)行自己的狀態(tài)紀(jì)錄時(shí)就需要用到state注益;

? 初始化:state的初始化可以在constructor中,通過this.state進(jìn)行設(shè)置溯捆,值必須為一個(gè)js對(duì)象的格式丑搔,通常將prop傳入的外部值賦給state,以便后續(xù)操作提揍;設(shè)置默認(rèn)值時(shí)啤月,可以用?| | 操作符進(jìn)行;

? 讀取和更新state

更新使用this.setState({count:this.state.count++})方法劳跃;

讀取為:this.state.count這種方式

? Prop和state的對(duì)比:

Prop:定義外部接口谎仲;賦值在外部環(huán)境使用組件時(shí);組件內(nèi)部不能更改

State:紀(jì)錄內(nèi)部狀態(tài)刨仑;賦值在組件內(nèi)部郑诺;在組件內(nèi)部可以進(jìn)行更改;


? reactcss的樣式書寫

? 全局引入css文件

此種方式會(huì)將css文件在全局引入杉武,也就是說當(dāng)前樣式文件中書寫的所有樣式辙诞,在任何一個(gè)組件都可以引用,此種引用方式有可能會(huì)造成全局的污染轻抱,變量名沖突飞涂,又或者說不符合組件式開發(fā)的思想;此種方式一般是引入全局的css文件祈搜;

import “app.css”


? 局部作用域(css modules的方式)

此種方式采用的是css modules的做法封拧,通過此做法,最后會(huì)將css文件中類名和dom中類名形成唯一的hash值夭问,這樣就不會(huì)造成類名的沖突了泽西,使用場(chǎng)景,一般為組件內(nèi)部的樣式防止全局書寫造成的類名污染缰趋;

比如如下寫法:

app.css:

.title {

??color:?red;

}

jsx:

import style from './App.css';

export default ()?=>?{

??return?(

????<h1 className={style.title}>

??????Hello World

????</h1>

??);

};

最后會(huì)編譯成如下代碼:

<h1 class="_3zyde4l1yATCOkgn-DBWEL">

??Hello World

</h1>

._3zyde4l1yATCOkgn-DBWEL {

??color:?red;

}


注:在css Modules中還提供了一種css全局作用域的書寫方式捧杉,也就是說如果通過此種方式注冊(cè)的css類名不會(huì)被替換為hash值陕见,書寫方式如下:

css

:global(.title){

color:red;

}


? 行內(nèi)樣式:

jsxdom上直接使用style屬性進(jìn)行樣式的設(shè)置,樣式的值為一個(gè)對(duì)象味抖,這種方式的書寫评甜,可以支持css樣式以js對(duì)象的方式進(jìn)行書寫,如果不想將組件的內(nèi)部樣式進(jìn)行作用域隔離使用css modules的方式進(jìn)行書寫仔涩,則可以此種方式進(jìn)行書寫忍坷,可以直接在render函數(shù)中定義樣式對(duì)象,也可以通過專門外部樣式js文件配置樣式對(duì)象熔脂,然后引入到dom進(jìn)行使用佩研,書寫方式如下:

var style={

color:red;

}

<div style={style}>天氣真好</div>

注:在書寫css屬性時(shí),一定要采用駝峰式寫法霞揉;

? 事件處理

? react中的事件綁定屬性采用的是駝峰式寫法:

<button onClick={this.clickfn}>點(diǎn)擊</button>

? 處理react使用class類定義方法時(shí)旬薯,無法自動(dòng)綁定this的弊端:

? constructor中使用bind為事件函數(shù)綁定this

this.clickfn=this.clickfn.bind(this)

? dom中調(diào)用函數(shù)時(shí),先使用箭頭函數(shù)綁定this适秩,箭頭函數(shù)的this是在定義時(shí)形成的

<button onClick={()=>this.clickfn()}>點(diǎn)擊</button>


? jsxonClickhtmlonclick不同之處


? htmlonclick弊端:

注冊(cè)的事件處理函數(shù)都是全局環(huán)境绊序,污染了全局環(huán)境;

使用onclick的dom元素秽荞,如果在dom樹中刪除時(shí)骤公,必須手動(dòng)的注銷事件處理器,否則會(huì)造成內(nèi)容泄露扬跋;


? jsxonClick:

掛載的每一個(gè)函數(shù)都是在組件內(nèi)部阶捆,而不是全局;

無論多少個(gè)onClick都是采用的事件委托的方式胁住,在dom樹頂層添加一個(gè)事件監(jiān)聽函數(shù)趁猴,此函數(shù)會(huì)根據(jù)具體組件分配具體的函數(shù)


? 條件判斷:

reactjsx語法中彪见,如果遇到js語句使用{}進(jìn)行包裹儡司;

? if語句的使用:


render() {

????????var?element=null

????????????if(this.state.stateT){

???????????????????element= <div > stateT為true時(shí)?< /div>

????????????????}else{

?????????????????????element= <div > stateT為false時(shí)?< /div>

????????????????}

????????return?(

????????????<div>

????????????????<button onClick={this.changeFn}>切換</button>

????????????????{element}

????????????</div>

????????)

????}


? jsx與運(yùn)算符&&的結(jié)合:


render(){

????????return?(

?????????????<div>

????????????????<button onClick={this.changeFn}>切換</button>

????????????????{this.state.stateT&& <div > stateT為false時(shí)?< /div>}

????????????</div>

????????)

????}

? 三目運(yùn)算符


render(){

????????return?(

?????????????<div>

????????????????<button onClick={this.changeFn}>切換</button>

????????????????{this.state.stateT?<div>stateT為true時(shí)</div>:<div> stateT為false時(shí)</div>}

????????????</div>

????????)

}

? jsx語法中,render可以返回null余指,表示不進(jìn)行任何dom的渲染捕犬,但是鉤子函數(shù)會(huì)執(zhí)行;

? 列表和keys

? 基礎(chǔ)用法:(key一般采用數(shù)據(jù)id酵镜,或者數(shù)據(jù)在數(shù)組中的索引)


render() {

????????var?element=this.state.list.map((i,index)=><li key={index}>{i}</li>)

????????return?(

????????????<div>

????????????????<button onClick={this.changeFn}>切換</button>

????????????????{element}

????????????</div>

????????)

}

注:如果后續(xù)進(jìn)行數(shù)據(jù)的重新排序碉碉,則最好不要使用索引當(dāng)作key值,否則淮韭,由于key值和dom的內(nèi)容同時(shí)改變垢粮,則會(huì)引起全部dom節(jié)點(diǎn)的重繪;如果使用的是id靠粪,則只會(huì)調(diào)整dom節(jié)點(diǎn)的順序蜡吧,不會(huì)引起重繪dom樹毫蚓;(可以用上面例子演示,推薦使用id作為標(biāo)識(shí)昔善,而不是index)

? key值只需要在兄弟元素之間唯一就可以元潘,不需要是在全局唯一的


render() {

????????var?element=this.state.list.map((i,index)=><li key={i}>{i}</li>)

????????var?element2=this.state.list.map((i,index)=><li key={i}>{i+1}</li>)

????????return?(

????????????<div>

????????????????<button onClick={this.changeFn}>切換</button>

????????????????{element}

????????????????{element2}

????????????</div>

????????)

??? ?}

? jsx中使用map進(jìn)行遍歷


render() {

????????return?(

????????????<ul>

????????????????<button onClick={this.changeFn}>切換</button>

???????????????{this.state.list.map((i)=><li key={i}>{i}</li>)}

????????????</ul>

????????)

????}

? 表單

vue中,我們知道由于vuemvvm架構(gòu)君仆,vm之間是響應(yīng)式的翩概,可以實(shí)時(shí)同步,但是在react中不存在數(shù)據(jù)的雙向數(shù)據(jù)綁定返咱,只是負(fù)責(zé)view層的渲染钥庇,所以我們?cè)?/b>react中取表單中的值時(shí)需要一定的方式

? 受控組件(采用react的單向數(shù)據(jù)流方式實(shí)現(xiàn)vue一樣的雙向數(shù)據(jù)綁定)

changeFn(event){

????????this.setState({

????????????name:event.target.value

????????})

????}

????render() {

????????return?(

????????????<div>

????????????????<p>表單</p>

????????????????<label htmlFor="name">name:</label>

????????????????<input type="text"?id="name"?value={this.state.name} onChange={this.changeFn}/>

????????????????<p>{this.state.name}</p>

????????????</div>

????????)

????}

如果想對(duì)從input中獲取到的值進(jìn)行格式化時(shí),則如下操作就可以實(shí)現(xiàn):

this.setState({

????????????name:event.target.value.toUpperCase()

????????})

? textarea標(biāo)簽在react中設(shè)置和讀取值都采用value的方式

? react中的使用select洛姑,并實(shí)時(shí)獲取其選擇的值:

render() {

????????return?(

????????????<div>

????????????????<p>表單</p>

????????????????<label htmlFor="name">name:</label>

????????????????<select value={this.state.name} onChange={this.changeFn}>

????????????????????<option value="one">one</option>

????????????????????<option value="two">two</option>

????????????????????<option value="three">three</option>

????????????????</select>

????????????????<p>{this.state.name}</p>

????????????</div>

????????)

}

? react中實(shí)現(xiàn)多表單元素值得獲取

changeFnAll(event){

????????let target=event.target

????????let name=target.name

????????let value=target.type==="checkbox"?target.checked:target.value

????????this.setState({

????????????[name]:value

????????})

????}

????// 實(shí)現(xiàn)多表單元素值的獲取

????render() {

????????return?(

????????????<div>

????????????????<p>表單</p> ???

????????????????<input type="checkbox"?value={this.state.checkbox} onChange={this.changeFnAll} name="checkbox"/>

????????????????<input type="text"?value={this.state.text} onChange={this.changeFnAll} ?name="text"/>

????????????????<p>{this.state.checkbox.toString()}</p>

????????????????<p>{this.state.text}</p>

????????????</div>

????????)

????}

? 組件間通訊

? 父組件向子組件傳遞數(shù)據(jù):

? 字符串常量的傳遞:

<MyComponent message="hello world"?/>

<MyComponent message={'hello world'} />

? 沒有給屬性傳值上沐,它默認(rèn)為?true

<MyTextBox autocomplete />

不建議如下寫法皮服,容易與es6的對(duì)象簡(jiǎn)潔表示法沖突

<MyTextBox autocomplete={true} />

? 使用擴(kuò)展運(yùn)算符進(jìn)行屬性的設(shè)置

??const?props =?{firstName:?'Ben', lastName:?'Hector'};

<Greeting {...props} />;

? 子組件向父組件傳遞數(shù)據(jù)

只能通過將父組件的一個(gè)方法用prop的方式傳入子組件楞艾,在子組件觸發(fā)更變時(shí),調(diào)用這個(gè)傳入的方法龄广,然后把子組件更變后的值以參數(shù)的形式傳入父組件硫眯;從而達(dá)到父組件和子組件的通信的效果;


? 兄弟組件間的通訊

? 狀態(tài)提升

對(duì)于沒有直接關(guān)聯(lián)關(guān)系的兩個(gè)節(jié)點(diǎn)择同,就如?Child_1 與?Child_2 之間的關(guān)系两入,他們唯一的關(guān)聯(lián)點(diǎn),就是擁有相同的父組件敲才。參考之前介紹的兩種關(guān)系的通訊方式裹纳,如果我們向由?Child_1 向?Child_2 進(jìn)行通訊,我們可以先通過?Child_1 向?Parent 組件進(jìn)行通訊紧武,再由?Parent 向?Child_2 組件進(jìn)行通訊

? 觀察者模式

也就是像angular和vue的事件派發(fā)機(jī)制剃氧,在這里react沒有內(nèi)置的事件派發(fā)模式,所以需要手動(dòng)封裝一個(gè)事件派發(fā)機(jī)制阻星;

如下代碼:

var?watchObj = {

????arrFn: {},

????on(name, fn) {

????????if?(this.arrFn[name] === undefined) {

????????????this.arrFn[name] = []

????????}

????????this.arrFn[name].push(fn)

????},

????emit() {

????????let?name, args;

????????if?(arguments.length == 0) {

????????????return?false;

????????}

????????name = arguments[0]

????????args = [].concat(Array.prototype.slice.call(arguments, 1));

????????if?(this.arrFn[name] !== undefined?&& this.arrFn[name].length > 0) {

????????????this.arrFn[name].forEach(function(i) {

????????????????i(...args)

????????????}, this);

????????}

????}

}

export?default?watchObj


? 組合與繼承

vue中的有一種組件特性叫內(nèi)容分發(fā)朋鞍,可以在父組件中自定義子組件的dom結(jié)構(gòu),在react中也提供了這么一種機(jī)制

? 包含關(guān)系:(在子組件通過this.props.children獲取父組件中寫在子組件開閉標(biāo)簽間的dom節(jié)點(diǎn))

父組件:

render() {

????????return?(

????????????<div>

???????????????<Children>

????????????????<p>相當(dāng)于vue的內(nèi)容分發(fā)</p>

???????????????</Children>

????????????</div>

????????)

????}

子組件:

render() {

????????return?(

????????????<div>

????????????????<p>這里是子組件</p>

???????????????{this.props.children}

????????????</div>

????????)

????}


? 子組件中動(dòng)態(tài)渲染其他組件:(在父組件中將其他組件動(dòng)態(tài)綁定到prop屬性上妥箕,在子組件中通過相應(yīng)的屬性來獲取)


父組件:

render() {

????????return?(

?????????var?one= <span>這里為true</span>

????????var?two=<span>這里為false</span>

????????return?(

????????????<div>

????????????????<Slot?one={one} two={two}></Slot>

????????????</div>

????????)

????????)

????}

子組件:

render() {

???????return?<div> ??

????? <p> ?這里是子組件</p>

????????{this.state.state?this.props.one:this.props.two}

????</div>

}


? react-router

?2.0 完全向后兼容?1.0滥酥,所有在?1.0 被棄用的?API 都會(huì)在控制臺(tái)以?warn 的形式打印出來,在?3.0 中將會(huì)完全移除?1.0 所棄用的東西畦幢,現(xiàn)在最新版本是4.2.0版本坎吻;但是4.0版本后,有很多方法不再向前兼容(這里講解的為2.8.1版本)


? 基本用法:

? 首先我們需要導(dǎo)入一些組件...

import { Router, Route, Link } from 'react-router'

? 配置路由信息:

? 使用jsx語法

React.render((

??<Router>

????<Route path="/"?component={App}>

??????<Route path="about"?component={About}?/>

??????<Route path="inbox"?component={Inbox}?/>

????</Route>

??</Router>

),?document.body)

? 使用js對(duì)象進(jìn)行配置

const?routes =?{

??path:?'/',

??component:?App,

??childRoutes:?[

????{?path:?'about',?component:?About },

????{?path:?'inbox',?component:?Inbox },

??]

}

React.render(<Router routes={routes}?/>,?document.body)

? 獲取參數(shù)

? 通過動(dòng)態(tài)路由片段

<Route path="messages/:id"?component={Message}?/>

?可以通過如下方式進(jìn)行獲取id

this.props.params.id

? 通過query字符串

/foo?bar=baz宇葱;

this.props.location.query.bar

? 路由的配置規(guī)則(Router

? 路徑語法:

? :paramName?– 匹配一段位于?/瘦真、???#?之后的?URL返奉。?命中的部分將被作為一個(gè)參數(shù)

? ()?– 在它內(nèi)部的內(nèi)容被認(rèn)為是可選的

? *?– 匹配任意字符(非貪婪的)直到命中下一個(gè)字符或者整個(gè)?URL 的末尾,并創(chuàng)建一個(gè)?splat?參數(shù)

如下解釋:

// 匹配?/hello/michael 和?/hello/ryan

<Route path="/hello/:name"> ????????

// 匹配?/hello, /hello/michael 和?/hello/ryan

<Route path="/hello(/:name)"> ??

// 匹配?/files/hello.jpg 和?/files/path/to/hello.jpg ?

<Route path="/files/*.*"> ?????????

? 常用路由類型:


browserHistory:react推薦使用(采用的是html5的瀏覽器路由紀(jì)錄)

hashHistory:默認(rèn)的(采用的是hash的瀏覽器路由紀(jì)錄)

createMemoryHistory


使用browserHistory如下:

import?{?browserHistory } from 'react-router'

<Router?history={browserHistory}>

? 路由的跳轉(zhuǎn)配置(Link):

需要?jiǎng)討B(tài)的引入組件:

import { Link} from “react-router“

<Link></Link>

屬性:

to: 值為字符串吗氏,例:”/list” (路由跳轉(zhuǎn)的路徑)芽偏;


query:值為對(duì)象,例:{name:1} (這里相當(dāng)于/list?name=1,這種路由的書寫方式)弦讽;


state:值為對(duì)象污尉,可以通過this.location.state獲取到當(dāng)前的值;


activeClassName:當(dāng)某個(gè)?route 是激活狀態(tài)時(shí)往产,<Link>?可以接收傳入的?className被碗。失活狀態(tài)下是默認(rèn)的?class。寫法如下:activeClassName="current"


activeStyle當(dāng)某個(gè)?route 是激活狀態(tài)時(shí)仿村,可以將樣式添加到鏈接元素上锐朴;寫法如下:activeStyle={{color: 'red'}}


onClick(e):自定義點(diǎn)擊事件的處理方法。如處理?<a>?標(biāo)簽一樣?- 調(diào)用?e.preventDefault()?來防止過度的點(diǎn)擊蔼囊,同時(shí)?e.stopPropagation()?可以阻止冒泡的事件


? 默認(rèn)路由的設(shè)置:

jsx:

<IndexRoute component={?Index?}/>

js對(duì)象:

const routes = {

??path:?'/',

??component:?App,

??indexRoute:{

????component:Index

??},

??childRoutes:?[

????{ path:?'list', component:?List?},

??]

}


在嵌套路由中使用{this.props.children}來渲染動(dòng)態(tài)路由焚志,這里相當(dāng)于vue-router中的router-view

? 路由對(duì)應(yīng)組件的渲染

? 單一組件的渲染:(this.props.children

路由:

????????????<Route?path='center'?component={Center}>

????????????????<Route?path="left"?component={Left}></Route>

????????????</Route>

組件:(Center

render(){

????????return?(

??????????<div>

????????????<p>這里是中心也</p>

????????????{this.props.children}

??????????</div>

????????)

???}

? 多組件的渲染


路由:

????????????<Route?path='center'?component={Center}>

???????????????<Route?path="left"?components={{left:Left,right:Right}}></Route>

????????????</Route>

組件:

render(){

const { left, right } = this.props

????????return?(

??????????<div>

????????????<p>這里是中心也</p>

????????????{left}-{right}

??????????</div>

????????)

???}

? 異步組件(組件的懶加載)

? 單組件路由的定義:(getComponent()方法使用)

注:這里采用的是webpackrequire.ensure()進(jìn)行的組件懶加載,接受三個(gè)參數(shù)畏鼓,第一個(gè)參數(shù)為加載當(dāng)前模塊時(shí)的依賴酱酬,第二個(gè)參數(shù)為加載的當(dāng)前的模塊的回掉函數(shù),第三個(gè)參數(shù)為加載完畢后模塊的名稱云矫;

這里的getComponent函數(shù)第一個(gè)參數(shù)為當(dāng)前路由的信息膳沽,第二個(gè)參數(shù)為一個(gè)回調(diào)函數(shù),這里的回掉函數(shù)遵循node.js的回掉函數(shù)風(fēng)格(回調(diào)函數(shù)的第一個(gè)參數(shù)為錯(cuò)誤的捕捉让禀,一般無錯(cuò)誤挑社,所以一般默認(rèn)填入null,第二個(gè)參數(shù)為異步裝載成功的組件巡揍;)


<Route?path="list"?getComponent={(location, cb) => {

????????????require.ensure([],(require)=>{

???????????????cb(null, require('./components/routerPage/list.jsx').default)

????????????},'List')

??????????}} />



? 多組件路由的定義:(getComponents方法)

<Route?path="center"?getComponents={(location, cb) => {

????????????require.ensure([],function(require){

???????????????cb(null, {center:require('./components/routerPage/center.jsx').default,list:require('./components/routerPage/center.jsx').default})

????????????},'Center')

? js對(duì)象的方式配置路由組件的懶加載

const routes = {

??path:?'/',

??getComponent(nextState, cb) {

????require.ensure([], (require) => {

??????cb(null, require('./components/app.jsx').default)

????}, 'App')

??},

??indexRoute:{

????getComponent(nextState, cb) {

??????require.ensure([], (require) => {

????????cb(null, require('./components/index.jsx').default)

??????}, 'Index')

????},

??},

??childRoutes:?[

????// require("./routes/listR.js").default

?????{

????????path:?'list',

????????getComponent(nextState, cb) {

????????????require.ensure([], (require) => {

????????????????cb(null, require('./components/routerPage/list.jsx').default)

????????????}, 'List')

????????}

????}

??]

}

? Route的鉤子函數(shù):(Route組件上書寫)

onEnter(nextState,?replaceState,?callback?)

當(dāng)?route 即將進(jìn)入時(shí)調(diào)用痛阻。它提供了下一個(gè)路由的?state,一個(gè)函數(shù)重定向到另一個(gè)路徑吼肥。this?會(huì)觸發(fā)鉤子去創(chuàng)建?route 實(shí)例录平。

當(dāng)?callback?作為函數(shù)的第三個(gè)參數(shù)傳入時(shí),這個(gè)鉤子將是異步執(zhí)行的缀皱,并且跳轉(zhuǎn)會(huì)阻塞直到?callback?被調(diào)用斗这。

onLeave()

當(dāng)?route 即將離開時(shí)調(diào)用

? 路由注入到組件的props上的屬性和參數(shù):

? history:路由的前端歷史紀(jì)錄和路由跳轉(zhuǎn)方法

go():

goBack():

goForward():

push():

replace()

? location:當(dāng)前路由的參數(shù)信息

state:通過在link上的state屬性設(shè)置的對(duì)象值

action:當(dāng)前路由的紀(jì)錄形式

pathname:當(dāng)前hash路由

query:通過路由的傳參,路徑啤斗?后的路徑表箭,或者是query屬性傳遞的

? params:通過動(dòng)態(tài)路由傳遞的值

? routeParams:(小心有坑)

this.props.params?是直接在組件中指定?route 的一個(gè)子集。例如钮莲,如果?route 的路徑是?users/:userId?而?URL 是?/users/123/portfolios/345免钻,那么?this.props.routeParams?會(huì)是?{userId:?'123'}彼水,并且?this.props.params?會(huì)是?{userId:?'123',?portfolioId:?345}。

? route:當(dāng)前路由的配置信息

? routes:當(dāng)前路由所包含的所有路由片段

? 在路由跳轉(zhuǎn)前阻止路由的跳轉(zhuǎn):

在組件內(nèi)部如下引入:

import?{?withRouter } from 'react-router'

組件拋出時(shí):

export default?withRouter(List)

組件回調(diào)函數(shù)的注冊(cè):

componentDidMount(){

?????????this.props.router.setRouteLeaveHook(

?????????????this.props.route,

?????????????this.routerWillLeave)

????}

????routerWillLeave(nextLocation) {

??????// 返回?false 會(huì)繼續(xù)停留當(dāng)前頁面极舔,

??????// 否則凤覆,返回一個(gè)字符串,會(huì)顯示給用戶拆魏,讓其自己決定

????????return?'確認(rèn)要離開盯桦?';

????}

? 數(shù)據(jù)的請(qǐng)求

constructorcomponentDidUpdate中(在進(jìn)入路由或者進(jìn)入路由的相應(yīng)組件內(nèi)部進(jìn)行數(shù)據(jù)請(qǐng)求);

withRouter進(jìn)入目標(biāo)路由或組件前渤刃,進(jìn)行數(shù)據(jù)的請(qǐng)求拥峦;


? PropTypes類型檢查

react15.5版本后,React.PropTypes已經(jīng)廢棄了卖子,需要單獨(dú)引入prop-types庫進(jìn)行驗(yàn)證

import?PropTypes?from 'prop-types'

class?Children extends?Component {

????constructor(props) {

????????super(props)

????}

???render() {

????????return?(

????????????<div>

????????????????<p>這里是子組件</p>

???????????????{this.props.name}

????????????</div>

????????)

????}

}

Children.propTypes={

????name:PropTypes.string

}


prop-types庫可以校驗(yàn)的類型如下:


import?PropTypes?from 'prop-types';

MyComponent.propTypes = {

??// 你可以將屬性聲明為以下?JS 原生類型

??optionalArray:?PropTypes.array,

??optionalBool:?PropTypes.bool,

??optionalFunc:?PropTypes.func,

??optionalNumber:?PropTypes.number,

??optionalObject:?PropTypes.object,

??optionalString:?PropTypes.string,

??optionalSymbol:?PropTypes.symbol,


??// 任何可被渲染的元素(包括數(shù)字略号、字符串、子元素或數(shù)組)洋闽。

??optionalNode:?PropTypes.node,


??// 一個(gè)?React 元素

??optionalElement:?PropTypes.element,


??// 你也可以聲明屬性為某個(gè)類的實(shí)例玄柠,這里使用?JS 的

??// instanceof 操作符實(shí)現(xiàn)。

??optionalMessage:?PropTypes.instanceOf(Message),


??// 你也可以限制你的屬性值是某個(gè)特定值之一

??optionalEnum:?PropTypes.oneOf(['News', 'Photos']),


??// 限制它為列舉類型之一的對(duì)象

??optionalUnion:?PropTypes.oneOfType([

????PropTypes.string,

????PropTypes.number,

????PropTypes.instanceOf(Message)

??]),


??// 一個(gè)指定元素類型的數(shù)組

??optionalArrayOf:?PropTypes.arrayOf(PropTypes.number),


??// 一個(gè)指定類型的對(duì)象

??optionalObjectOf:?PropTypes.objectOf(PropTypes.number),


??// 一個(gè)指定屬性及其類型的對(duì)象

??optionalObjectWithShape:?PropTypes.shape({

????color:?PropTypes.string,

????fontSize:?PropTypes.number

??}),


??// 你也可以在任何?PropTypes 屬性后面加上?`isRequired`

??// 后綴喊递,這樣如果這個(gè)屬性父組件沒有提供時(shí)随闪,會(huì)打印警告信息

??requiredFunc:?PropTypes.func.isRequired,


??// 任意類型的數(shù)據(jù)

??requiredAny:?PropTypes.any.isRequired,


??// 你也可以指定一個(gè)自定義驗(yàn)證器阳似。它應(yīng)該在驗(yàn)證失敗時(shí)返回

??// 一個(gè)?Error 對(duì)象而不是?`console.warn` 或拋出異常骚勘。

??// 不過在?`oneOfType` 中它不起作用。

??customProp:?function(props, propName, componentName) {

????if?(!/matchme/.test(props[propName])) {

??????return?new?Error(

????????'Invalid prop `'?+ propName + '` supplied to'?+

????????' `'?+ componentName + '`. Validation failed.'

??????);

????}

??},


??// 不過你可以提供一個(gè)自定義的?`arrayOf` 或?`objectOf`

??// 驗(yàn)證器撮奏,它應(yīng)該在驗(yàn)證失敗時(shí)返回一個(gè)?Error 對(duì)象俏讹。?它被用

??// 于驗(yàn)證數(shù)組或?qū)ο蟮拿總€(gè)值。驗(yàn)證器前兩個(gè)參數(shù)的第一個(gè)是數(shù)組

??// 或?qū)ο蟊旧硇蟮酰诙€(gè)是它們對(duì)應(yīng)的鍵泽疆。

??customArrayProp:?PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {

????if?(!/matchme/.test(propValue[key])) {

??????return?new?Error(

????????'Invalid prop `'?+ propFullName + '` supplied to'?+

????????' `'?+ componentName + '`. Validation failed.'

??????);

????}

??})

};

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市玲献,隨后出現(xiàn)的幾起案子殉疼,更是在濱河造成了極大的恐慌,老刑警劉巖捌年,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓢娜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡礼预,警方通過查閱死者的電腦和手機(jī)眠砾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來托酸,“玉大人褒颈,你說我怎么就攤上這事柒巫。” “怎么了谷丸?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵堡掏,是天一觀的道長。 經(jīng)常有香客問我刨疼,道長布疼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任币狠,我火速辦了婚禮游两,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘漩绵。我一直安慰自己贱案,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布止吐。 她就那樣靜靜地躺著宝踪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪碍扔。 梳的紋絲不亂的頭發(fā)上瘩燥,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音不同,去河邊找鬼厉膀。 笑死,一個(gè)胖子當(dāng)著我的面吹牛二拐,可吹牛的內(nèi)容都是我干的服鹅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼百新,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼企软!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起饭望,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤仗哨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后铅辞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厌漂,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年巷挥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了桩卵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖雏节,靈堂內(nèi)的尸體忽然破棺而出胜嗓,到底是詐尸還是另有隱情,我是刑警寧澤钩乍,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布辞州,位于F島的核電站,受9級(jí)特大地震影響寥粹,放射性物質(zhì)發(fā)生泄漏变过。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一涝涤、第九天 我趴在偏房一處隱蔽的房頂上張望媚狰。 院中可真熱鬧,春花似錦阔拳、人聲如沸崭孤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辨宠。三九已至,卻和暖如春货裹,著一層夾襖步出監(jiān)牢的瞬間嗤形,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國打工弧圆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赋兵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓墓阀,卻偏偏與公主長得像毡惜,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子斯撮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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

  • React框架學(xué)習(xí) React的起源和發(fā)展 起初facebook在建設(shè)instagram(圖片分享)的時(shí)候嘞,因?yàn)?..
    hcySam閱讀 672評(píng)論 0 1
  • 函數(shù)是面向過程的扶叉,函數(shù)的調(diào)用不需要主體勿锅,而方法是屬于對(duì)象的,調(diào)用方法需要一個(gè)主體-即對(duì)象枣氧。 npm install...
    Gukson666閱讀 467評(píng)論 0 3
  • 1. React簡(jiǎn)介 React 起源于 Facebook 的內(nèi)部項(xiàng)目溢十,因?yàn)樵摴緦?duì)市場(chǎng)上所有 JavaScrip...
    王蕾_fd49閱讀 409評(píng)論 0 0
  • #React框架的學(xué)習(xí)# React的起源和發(fā)展 起初facebook在建設(shè)instagram(圖片分享)的時(shí)候因...
    你好愛人i閱讀 702評(píng)論 0 1
  • 夜鶯2517閱讀 127,719評(píng)論 1 9