JSX
2019.10.08
const 聲明一個(gè)變量
const 變量名 = (內(nèi)容);
內(nèi)容可以是
"字符串"
<標(biāo)簽名>標(biāo)簽內(nèi)容{表達(dá)式}</標(biāo)簽名>
表達(dá)式可以是任何 js 表達(dá)式,(for 循環(huán)不行,不知道為啥)
JSX 本身也是一個(gè)表達(dá)式
語(yǔ)法上更接近 js 而不是 html,所以使用駝峰命名
JSX 元素渲染
React 元素
使用 ReactDOM.render();來(lái)渲染根節(jié)點(diǎn),并傳入 你想渲染的React元素
語(yǔ)法:
ReactDOM.render(元素名, document.getElementById('root'));
更新 UI 的唯一方式是創(chuàng)建一個(gè)全新的元素并將其傳入 ReactDOM.render();
在實(shí)踐中,大多數(shù) React 應(yīng)用只會(huì)調(diào)用一次ReactDOM.render();
通過(guò) setState() 方法可以刷新界面
JSX組件
使用 JS 函數(shù)來(lái)自定義組件:
function 組件名(形參){
return <標(biāo)簽名>標(biāo)簽內(nèi)容{形參.屬性名}</標(biāo)簽名>;
}
調(diào)用自定義的組件:
const 變量名 = <函數(shù)名 屬性名=屬性值 />
當(dāng) React 元素為自定義組件時(shí),它會(huì)將 JSX 所接收的屬性轉(zhuǎn)換成一個(gè)單個(gè)對(duì)象傳遞給組件,這個(gè)對(duì)象被稱(chēng)之為"props",訪(fǎng)問(wèn)屬性參數(shù)時(shí)使用:props.屬性名
組件參數(shù)也可以直接傳一個(gè) model
組件名稱(chēng)必須以大寫(xiě)字母開(kāi)頭
組件也可以寫(xiě)成class 組件,寫(xiě)法如下:
class 組件名 extends Component {
render() {
return (
<div>
{this.props.參數(shù)名.屬性名}
</div>
);
}
}
*為了嚴(yán)謹(jǐn)起見(jiàn),我會(huì)將所有的組件均采用以上定義為 class 的寫(xiě)法
組件可以理解為 app 開(kāi)發(fā)中的自定義 view,其本質(zhì)可以看做是類(lèi)
props 屬性
props 屬性是組件中自帶的屬性之一,其可以理解為該組件接收到的參數(shù)的一個(gè)集合.在使用 class 方式聲明組件時(shí)不需要寫(xiě)出該屬性,在給組件賦值時(shí),所有的參數(shù)都作為 props 的一個(gè)屬性獲取.
*可以理解為隱形的參數(shù)集合
State 屬性
State 是組件中自帶的屬性之一,當(dāng)組件中的元素被指定為 State 的值后,State 的值改變,該元素會(huì)相應(yīng)進(jìn)行刷新(相當(dāng)于數(shù)據(jù)綁定).
只有使用class 方式聲明的組件才能調(diào)用 state屬性,調(diào)用方式:
<標(biāo)簽名>this.state.屬性名</標(biāo)簽名>
在給 state 屬性賦值時(shí)標(biāo)簽內(nèi)容會(huì)自動(dòng)改變,賦值方式:
this.setState({屬性名: 屬性值});
*使用 "=" 等于號(hào)的方式賦值是無(wú)效的,組件不會(huì)被重新渲染(不知道數(shù)據(jù)會(huì)不會(huì)變)
構(gòu)造函數(shù)是唯一可以給 this.state 賦值的地方
state 的變量可以單獨(dú)被更新
組件的生命周期函數(shù):
1構(gòu)造函數(shù):
constructor(props) {
super(props);
//代碼...
};
}
2渲染
render(){
//代碼
}
3組件已經(jīng)被掛載
componentDidMount() {
//代碼
}
4組件即將被卸載
componentWillUnmount() {
//代碼
}
組件的state數(shù)據(jù)是向下流動(dòng)的
相當(dāng)于父視圖的 state可以傳遞給子視圖,子視圖無(wú)法傳遞數(shù)據(jù)給父視圖
箭頭函數(shù): 適合用作匿名函數(shù)
function 函數(shù)名 (參數(shù)1,參數(shù) 2) {函數(shù)聲明}
等同于
(參數(shù)1,參數(shù) 2) => {函數(shù)聲明}
單一表達(dá)式可以省略 return 和 {}
單一參數(shù)可以省略()
2019.10.09
事件處理
React 的事件命名采用小駝峰式而不是純小寫(xiě)
使用JSX語(yǔ)法時(shí)需要傳入一個(gè)函數(shù)作為事件處理函數(shù)而不是一個(gè)字符串
語(yǔ)法:
<控件名 事件名={事件處理函數(shù)名}>控件內(nèi)容</控件名>
如要阻止默認(rèn)行為,需要在事件中調(diào)用
props.preventDefault();
方法
在定義組件時(shí),通常將事件處理函數(shù)聲明為 class 中的方法,此時(shí)需要在constructor方法中進(jìn)行 this 綁定,語(yǔ)法如下:
// 為了在回調(diào)中使用 this,這個(gè)綁定是必不可少的
this.事件函數(shù)名 = this.事件函數(shù)名.bind(this);
*在 class 內(nèi)部聲明函數(shù)時(shí)不需要加 function 前綴
*在 class 內(nèi)部不需要聲明屬性,直接用 State 就行
向事件函數(shù)傳遞參數(shù),語(yǔ)法如下:
<標(biāo)簽名 事件名={this.事件函數(shù)名.bind(this, 參數(shù))}>標(biāo)簽內(nèi)容</標(biāo)簽名>
例如:
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
取出參數(shù)的語(yǔ)法如下:
handleClick(props){
//這里寫(xiě)了一個(gè)阻止默認(rèn)事件的方法
props.preventDefault();
}
條件渲染
即通過(guò) if 語(yǔ)句,三目運(yùn)算符或 && 與運(yùn)算符進(jìn)行元素的渲染
if 語(yǔ)句沒(méi)什么難的,語(yǔ)法如下:
render() {
let 變量名;
if(條件){
//條件成立
變量名=<標(biāo)簽 1></標(biāo)簽 1>
}else{
//條件不成立
變量名=<標(biāo)簽 2></標(biāo)簽 2>
}
return (
<div>
{變量名}
</div>
);
}
與運(yùn)算符語(yǔ)法如下,比較新穎:
<div>
{條件語(yǔ)句 &&
<標(biāo)簽名>
標(biāo)簽內(nèi)容
</標(biāo)簽名>
}
</div>
*之所以能這樣做,是因?yàn)樵?JavaScript 中,true && expression總是會(huì)返回 expression, 而 false && expression 總是會(huì)返回 false。因此,如果條件是 true,&& 右側(cè)的元素就會(huì)被渲染,如果是 false,React 會(huì)忽略并跳過(guò)它。
三目運(yùn)算符語(yǔ)法如下:
{條件語(yǔ)句 ? (<標(biāo)簽></標(biāo)簽>) : (<標(biāo)簽></標(biāo)簽>)}
可以通過(guò)讓 render() 方法直接 return null; 的方式來(lái)阻止組件的渲染.
*在組件的 render 方法中返回 null 并不會(huì)影響組件的生命周期。componentDidUpdate 依然會(huì)被調(diào)用。
列表
map()函數(shù),相當(dāng)于 forin 循環(huán),寫(xiě)法如下:
數(shù)組.map((item) => (<標(biāo)簽>{item}</標(biāo)簽>));
或
數(shù)組.map(function(item) {return (<標(biāo)簽>{item}</標(biāo)簽>)})
其返回值是一個(gè)新的數(shù)組,可以定義變量來(lái)接收它
key
列表需要一個(gè) key用來(lái)幫助 React 識(shí)別哪些元素改變了,因此需要給 map()方法里的元素附一個(gè) key 值,,通常使用元素的 id 來(lái)作為 key,當(dāng)數(shù)組的順序不變時(shí),當(dāng)不顯式賦值時(shí),React 會(huì)默認(rèn)使用 index 給 key 賦值.賦值方法如下:
const todoItems = 數(shù)組.map((item) =>
<li key={item.id}>
{item.text}
</li>
);
*所有在 map()方法中創(chuàng)建的元素都需要設(shè)置 key 屬性,其子元素不需要
同一個(gè) map()方法中創(chuàng)建的元素的 key 應(yīng)當(dāng)是獨(dú)一無(wú)二的,不同 map 方法中的元素的 key 可以是相同的
key 屬性是無(wú)法被讀取的,如需訪(fǎng)問(wèn)其值,需要設(shè)置其他的屬性名
表單
受控組件
在 HTML 中,表單組件是自帶狀態(tài)的,而在 React 中使用受控組件,即將表單元素的狀態(tài)"value"儲(chǔ)存至組件的 State 中,同時(shí)在渲染時(shí)其狀態(tài)也從 State 中獲取,這樣就可以在表單元素的 value 改變時(shí)動(dòng)態(tài)獲取到其 value.
代碼如下:
class 組件名 extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.回調(diào)函數(shù) = this.回調(diào)函數(shù).bind(this);
}
回調(diào)函數(shù)(event) {
this.setState({value: event.target.value});
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" value={this.state.value} onChange={this.回調(diào)函數(shù)} />
</form>
);
}
}
*其思想在于動(dòng)態(tài)改變 state 和根據(jù) state 動(dòng)態(tài)刷新表單組件.
*可以將數(shù)組傳入 value 屬性中
<input type="file" />
是一個(gè)非受控組件,因?yàn)槠?value 只讀
當(dāng)組件中有多個(gè)受控元素時(shí),可以給每個(gè)元素添加 name 屬性,并通過(guò)判斷 name 屬性的值來(lái)進(jìn)行相應(yīng)的操作.
給 state 賦值時(shí)的語(yǔ)法:
this.setState({
[name]: value
});
*setState 方法可以自動(dòng)合并屬性,所以調(diào)用其可以更改部分屬性.其方式類(lèi)似于OC中的字典寫(xiě)值操作(可以將 state 當(dāng)做一個(gè)字典)
當(dāng)受控組件的 value 設(shè)置為{null}時(shí)其值可被更改,如下:
ReactDOM.render(<input value="hi" />, mountNode);//不可更改
ReactDOM.render(<input value={null} />, mountNode);//可更改
狀態(tài)提升
由于 React 組件這個(gè)東西沒(méi)有類(lèi)似于iOS開(kāi)發(fā)的公開(kāi)屬性和私有屬性的概念,也沒(méi)有代理和回調(diào),所以當(dāng)其子控件向父控件傳值時(shí),使用的是類(lèi)似于原生開(kāi)發(fā)中 block 的方式進(jìn)行的.
父控件通過(guò)傳入一個(gè)方法作為屬性,并實(shí)現(xiàn)該方法,子控件調(diào)用該方法并傳入?yún)?shù),由父控件實(shí)現(xiàn)該方法.(這不就是 block 嘛)
在 React 中通常由父子控件使用該方式傳值,且由子控件傳遞給父控件,所以該方式被稱(chēng)之為 狀態(tài)提升.
語(yǔ)法:
父控件:
class 父控件 extends React.Component {
constructor(props) {
super(props);
this.block1 = this.block1.bind(this);
this.block2 = this.block2.bind(this);
this.state = {屬性: '' "};
}
block1(參數(shù)名) {
this.setState({屬性:參數(shù)名});
}
block2(參數(shù)名) {
this.setState({屬性:參數(shù)名});
}
render() {
return (
<div>
<子控件
參數(shù)={this.state.屬性}
block={this.block1} />
<子控件
參數(shù)={this.state.屬性}
onTemperatureChange={this.block2} />
</div>
);
}
}
子控件:
class 子控件 extends React.Component {
constructor(props) {
super(props);
this.事件回調(diào) = this.事件回調(diào).bind(this);
}
事件回調(diào)(event) {
this.props.block(event.target.value);
}
render() {
return (
<fieldset>
<input value={this.props.參數(shù)}
onChange={this.事件回調(diào)} />
</fieldset>
);
}
}
*在需要外傳參數(shù)時(shí),子控件不能使用自己的 this.state,而是需要調(diào)用 this.block(參數(shù))
組合
包含關(guān)系
在組件中使用一個(gè)名為"children"的數(shù)組來(lái)將子組件傳遞到子組件中 代碼如下:
function 子組件(props) {
return (
<div 屬性名=屬性值>
{props.children}
</div>
);
}
*這個(gè)傳遞是隱式的,但是當(dāng)你在組件的內(nèi)容中寫(xiě)了代碼而未在rander 中調(diào)用 props.children 時(shí),這些代碼是無(wú)效的,其未執(zhí)行 rander 故無(wú)法被渲染
繼承
繼承的關(guān)鍵字是 extend,在實(shí)際開(kāi)發(fā)時(shí)通常通過(guò)組合來(lái)實(shí)現(xiàn)組件的復(fù)用,并不需要使用繼承
React 總結(jié)
從移動(dòng)端開(kāi)發(fā)的角度來(lái)看,React類(lèi)似于使用代碼構(gòu)建界面中的 view,但是要意識(shí)到,相比于移動(dòng)端開(kāi)發(fā)而言,前端是基于界面的,而移動(dòng)端是基于代碼的,移動(dòng)端的一切界面都可以通過(guò)代碼調(diào)用API 來(lái)實(shí)現(xiàn),而前端的 js 是無(wú)法做到這一點(diǎn)的,還需要 html 和 css 的配合,React 僅僅是適用于 js 的框架,而開(kāi)發(fā)時(shí)還需要 css 的配合才能構(gòu)建起美觀(guān)的界面.
React 最重要的特點(diǎn)就是組件,通過(guò)組件的組合可以構(gòu)建各種不同的視圖效果,也讓代碼更加容易被復(fù)用.
JSX 僅僅是使用 React 的語(yǔ)法擴(kuò)展.其最大特點(diǎn)是可以在大括號(hào)內(nèi)書(shū)寫(xiě)表達(dá)式.