react官網(wǎng)教程基礎(chǔ)解析
1、使用redux和沒(méi)有redux,react寫法有什么不同嗎?
答:組件寫法一樣,但是state不一定交給組件內(nèi)部管理,可能放到store上統(tǒng)一管理。
2、認(rèn)識(shí)react,一個(gè)hello world!
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
3、如何使用react?
答:推薦你使用ES6語(yǔ)法來(lái)寫react,首先你需要Babel編譯你的ES6代碼,其次,你才可以使用比如 => (箭頭函數(shù)),class(類),模板文字,let和const語(yǔ)句等ES6語(yǔ)法。
4、JSX介紹
答:JSX是一種表達(dá)式,它有一個(gè)根標(biāo)簽,在內(nèi)部可以嵌入表達(dá)式,使用{}(大括號(hào))包裹起來(lái)。它看起來(lái)就是html的一部分,或者叫一個(gè)html模塊。
class T extends React.Component {
render() {
return <div className="left-enter" style={}>{value}</div>
}
}
從上面的代碼例子你可以看到幾個(gè)和html不同的地方,class =》className,style是一個(gè)object,你還可以在dom元素中使用{}插入數(shù)據(jù)。
使用JSX還可以防止XSS(跨站腳本攻擊),因?yàn)镴SX只是表達(dá)式,它需要先轉(zhuǎn)換成字符串,然后才能渲染到真實(shí)DOM上面,但對(duì)于真正的黑客來(lái)說(shuō),這種做法也不是安全的。
4、元素和組件的概念
react組件:
class T extends React.Component {
render() {
return <div className="left-enter" style={}>{value}</div>
}
}
react元素:
<div className="left-enter" style={}>{value}</div>
5、組件的使用
函數(shù)組件:函數(shù)組件沒(méi)有狀態(tài)和生命周期,但是你可以返回一個(gè)react元素。
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
class組件:非常強(qiáng)大,有自己的state和生命周期。和函數(shù)組件一樣,class組件也需要返回一個(gè)react元素。
class Welcome extends React.Component {
componentWillMount() {}
componentDidMount() {}
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
在一個(gè)龐大復(fù)雜的網(wǎng)站應(yīng)用中,要如何拆分組件呢?官網(wǎng)上說(shuō)組件拆分的越細(xì),復(fù)用性就越強(qiáng),從實(shí)際開發(fā)中來(lái)看,這個(gè)說(shuō)法沒(méi)有錯(cuò),但是
會(huì)帶來(lái)一個(gè)比較嚴(yán)重的問(wèn)題,就是組件太多,管理起來(lái)不方便。有人使用第三方react組件的時(shí)候,只有那些文檔非常強(qiáng)大的開源組件
才能給你的開發(fā)提高效率。如果你自己的組件也想拆分到細(xì)致,那么寫好文檔是最重要的一步。
react還提到了一點(diǎn),傳遞給組件的數(shù)據(jù)是"只讀"的,要保證組件中的數(shù)據(jù)是"純數(shù)據(jù)",輸入即輸出。那么,如果你需要在組件中修改props.data
該怎么做呢?
render() {
const { data } = this.props
//定義一個(gè)新的變量來(lái)保存修改后的值。
let _data = data + 1;
}
6、組件的狀態(tài)和生命周期
前面我們提到組件分為函數(shù)組件和類組件,函數(shù)組件是無(wú)狀態(tài),類組件有狀態(tài)和生命周期。
什么是狀態(tài)?
答:通俗理解,就是組件不同時(shí)候的不同表現(xiàn),比如,一個(gè)按鈕組件,可能有激活狀態(tài),不可點(diǎn)擊狀態(tài),顯示狀態(tài),隱藏狀態(tài)等,在react用state來(lái)保存這些狀態(tài)。
而state本身不僅僅表示組件狀態(tài),還可以保存組件的數(shù)據(jù)。
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
isShow: true,
text: props.text,
disabled: true
};
}
render() {
const { isShow, text, disabled} = this.state
return <button disabled={disabled} style={{display: isShow ? "block" : "none"}}>{text}</button>
}
}
如果要修改state,請(qǐng)使用,注意,你不能在render函數(shù)里面直接修改state,而是要通過(guò)事件去觸發(fā)state更新。
this.setState({
isShow: false,
disabled: false
})
由于setState有批處理功能,所以該方法可能不一定同步更新,如果你需要依賴上一次的狀態(tài)和本次狀態(tài)的計(jì)算,那么需要寫成下面這種形式。
this.setState((prevState, props) => {
text: prevState.text++
});
demo網(wǎng)址:http://codepen.io/hyy1115/pen/GmdOKJ?editors=0011
有時(shí)候,子組件不需要關(guān)注自身的狀態(tài),而是通過(guò)父組件的狀態(tài)來(lái)改變,這時(shí)候的子組件可以寫成函數(shù)形式,通過(guò)props傳遞父組件給的狀態(tài)。
react生命周期
生命周期表示組件的一生,從出生到輝煌到死亡,中間最主要也是最常用的3個(gè)狀態(tài)是:
componentWillMount:出生了,把組件的狀態(tài)和屬性都設(shè)置好。
componentDidMount:渲染出來(lái)了,我不再是JSX,而是真實(shí)DOM了。
componentWillUnmount:要死了,死之前把遺產(chǎn)處理好。
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
isShow: true,
text: props.text,
disabled: true
};
}
componentWillMount() {
//出生了,可以給我數(shù)據(jù)和設(shè)置我的狀態(tài)
}
componentDidMount() {
//活著多好
}
componentWillUnmount() {
//要死了,把我的一生痕跡都清除
}
render() {
const { isShow, text, disabled} = this.state
return <button disabled={disabled} style={{display: isShow ? "block" : "none"}}>{text}</button>
}
}
還有其他幾個(gè)生命周期,并不是非常常用,需要用到的時(shí)候去看下別人的博客。
7、事件處理
<button onClick={(e) => this.handleClick(e)}>
按鈕
</button>
<input type="text" onChange={(e) => this.handleClick(e)} />
8、條件渲染
前面button的例子我們已經(jīng)使用到了條件渲染,條件渲染通過(guò)state來(lái)判斷,常用的是控制style、className、DOM屬性,JSX。
舉幾個(gè)常用的例子。
render() {
return (
<div>
{
this.state.isShow && <button>按鈕</button>
}
</div>
)
}
render() {
return (
<div>
{
this.state.isShow ? <button>按鈕</button> : <span>文本</span>
}
</div>
)
}
render() {
return <button disabled={this.state.disabled}>按鈕</button>
}
9、列表渲染
2個(gè)注意點(diǎn):
數(shù)組要判斷是否為空;
必須給一個(gè)key。
render() {
const { arr } = this.state
return arr.length > 0 && arr.map((value, key) => <li key={key}>{value}</li> )
}
10、表單
我曾經(jīng)經(jīng)歷過(guò)的一次阿里的面試,就考到了react表單的知識(shí)點(diǎn)。
受控組件:由react控制輸入的表單組件。
在下面的例子中,input的value值由state來(lái)決定,用戶輸入觸發(fā)onChange事件,然后更新state,達(dá)到修改value的目的。
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
return (
<input type="text" value={this.state.value} onChange={this.handleChange} />
);
}
}
或許你沒(méi)看出來(lái)和正宗input元素的區(qū)別,看一個(gè)真實(shí)DOM元素的例子,value由inupt自身維護(hù),我們沒(méi)有給value綁定值。
<input type="text">
textarea和input是一樣的用法。
select有些許不同,將value綁定到select上,而不是option。
<select value={this.state.value} onChange={this.handleChange}>
<option value="1">1</option>
<option value="2">2</option>
</select>
還有一種是多個(gè)輸入框的情況,比如登錄,有賬號(hào)、密碼等,這時(shí)候操作這些不同的input可以通過(guò)ref或者name,class,id等方法去setState,看
官方demo。
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
<form>
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
<input
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</form>
);
}
}
不受控組件:很簡(jiǎn)單,就是DOM自己維護(hù)狀態(tài)的組件,不受react控制。你可以給它設(shè)置defaultValue,但是不能去setState。
<input type="text" ref={(input) => this.input = input} defaultValue="默認(rèn)值"/>
相信有人會(huì)試過(guò)設(shè)置defaultValue之后執(zhí)行了setState去修改value,這樣做控制臺(tái)會(huì)發(fā)出警告。
總結(jié):受控組件是指受react控制的組件,表單組件中的value和state同步,不受控組件是指不受react控制的組件,表單組件中的
value不通過(guò)state同步,只能操作DOM去讀取value。
11、狀態(tài)提升
你一定聽說(shuō)過(guò)變量提升,函數(shù)提升,那么狀態(tài)提升是什么呢?
首先你得了解雙向綁定和單向數(shù)據(jù)流,雙向綁定中,數(shù)據(jù)可以在不同的組件之間實(shí)現(xiàn)共享,這樣做的確有很大的好處,但是在react中,
不推薦使用雙向綁定,而是使用狀態(tài)提升的方式。
記得和阿里的一個(gè)面試官聊的時(shí)候,他要求我用react實(shí)現(xiàn)雙向綁定,而我認(rèn)為react應(yīng)該采用狀態(tài)提升來(lái)實(shí)現(xiàn)。最后沒(méi)說(shuō)服他,或許讓Dan來(lái)
和他聊聊才有用,哈哈。
狀態(tài)提升:state推崇單向數(shù)據(jù)流,數(shù)據(jù)從父組件通過(guò)props流向子組件,如果你在子組件中,需要修改state來(lái)和其他子組件共享數(shù)據(jù)更新,
你需要使用回調(diào)函數(shù)給使數(shù)據(jù)更新給父組件,然后從父組件流向其他的子組件,這樣做是保證數(shù)據(jù)有單一的來(lái)源。
如果實(shí)子組件和子組件之間任意共享數(shù)據(jù),那么,后期維護(hù)會(huì)比較痛苦,特別是找bug的時(shí)候。
看一個(gè)狀態(tài)提升的例子吧。
class Child extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.upDateValue(e.target.value);
}
render() {
const {name, value} = this.props;
return (
<div>
<p>{name}:</p>
<input value={value}
onChange={this.handleChange}
/>
</div>
);
}
}
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {value: '', name: ''};
this.upDateValue = this.upDateValue.bind(this);
}
upDateValue(value) {
this.setState({value: value})
}
render() {
const {value} = this.state;
return (
<div>
<Child name="組件1" value={value} upDateValue={this.upDateValue} />
<Child name="組件2" value={value} upDateValue={this.upDateValue} />
</div>
);
}
}
ReactDOM.render(
<Demo />,
document.getElementById('root')
);
demo網(wǎng)址:http://codepen.io/hyy1115/pen/xdjoZQ?editors=0011
12、選擇組合還是繼承?
用過(guò)原生js或者jQuery的同學(xué)可能對(duì)基礎(chǔ)非常熟悉,繼承可以實(shí)現(xiàn)擴(kuò)展很多功能。
在react組件開發(fā)中,我們的每個(gè)react組件都是繼承于React.Component。
class MyComponent extends React.Component {
}
我們不推薦你繼承MyComponent。
//不推薦
class NextComponent extends MyComponent {
}
你應(yīng)該充分利用react組件的強(qiáng)大性能,開發(fā)各種你需要的組件繼承至React.Component。組件之間的嵌套非常強(qiáng)大,你可以嵌套函數(shù)組件,嵌套類組件。
詳情前往:https://facebook.github.io/react/docs/composition-vs-inheritance.html