安裝:
概述
- React起源于FaceBook的內(nèi)部項(xiàng)目,因?yàn)樵摴緦?duì)市場(chǎng)上所有的JavaScript MVC框架都不滿意,就決定自己寫一套用來(lái)假設(shè)Instagram的網(wǎng)站,2013年5月開源。
- 一般有三個(gè)庫(kù)文件,react.js,react-dom.js和Browser.js,它們必須首先加載,其中react.js是React的核心庫(kù),react-dom.js是提供與DOM相關(guān)的功能,Browser.js的作用是將JSX的語(yǔ)法轉(zhuǎn)換為JavaScript語(yǔ)法,這一步很消耗時(shí)間,最好放到服務(wù)器完成。
- script標(biāo)簽的type屬性:
- 自己書寫的js代碼,script標(biāo)簽的type屬性要改成:text/babel,這是因?yàn)镽eact獨(dú)有的JSX語(yǔ)法跟javaScript不兼容。凡是使用JSX的地方都要加上type="text/balbel"
- $babel src --out build :將src子目錄的js文件進(jìn)行語(yǔ)法轉(zhuǎn)換,轉(zhuǎn)碼后的文件全部放在build子目錄
核心:
ReactDoM.render()
- 是React的最基本的用法,用于將模板轉(zhuǎn)為HTML語(yǔ)言,并插入指定的DOM節(jié)點(diǎn)。
JSX語(yǔ)法:
- 概述:JavaScript的擴(kuò)展語(yǔ)法。JSX用來(lái)聲明React當(dāng)中的元素。
- 基本解析規(guī)則:遇到HTML標(biāo)簽(以<開頭),就用HTML規(guī)則解析,遇到代碼塊(以{開頭的),就用javascript規(guī)則解析。
- 書寫規(guī)則:一般都會(huì)帶上換行和縮進(jìn),增強(qiáng)代碼可讀性。同時(shí)在JSX代碼紋面擴(kuò)上一個(gè)小括號(hào),這樣可以防止分號(hào)自動(dòng)插入的bug,
- eg1:
var names = ['alice', 'emily', 'kate'];
ReactDOM.render(
<div>
{
names.map(function (name){
return <div key={v.toString()}>Hello,{name}!</div>
})
}
</div>, // 注意使用循環(huán)結(jié)構(gòu)時(shí)要添加key
document.getElementById('example')
);
//運(yùn)行結(jié)果:
- eg2:
const element = <h1>Hellow, world!</h1>
- 可以用引號(hào)來(lái)定義以字符串為值的屬性:
const element = <div tabIndex = "0></div>;
- 使用大括號(hào)來(lái)定義以javascript表達(dá)式為值得屬性:
const element = <img src = {user.avatarUrl}/>
- 注意
- 如果使用了大括號(hào)包裹javascrit表達(dá)式,就不要在外面用引號(hào)了。JSX會(huì)將引號(hào)當(dāng)中的內(nèi)容識(shí)別為字符串而不是表達(dá)式
- 因?yàn)镴SX的特性更接近Javascript所以使用駝峰命名來(lái)定義屬性名。
- 想要給渲染出的html標(biāo)簽添加一個(gè)類名要寫成:className = "類名",不能用class
- JSX防注入攻擊:
- 可以放心的在JSX中使用用戶輸入,ReactDom在渲染之前會(huì)默認(rèn)過(guò)濾所用傳入的值。他可以確保你的應(yīng)用不會(huì)被注入攻擊。所有內(nèi)容在渲染之前都被轉(zhuǎn)換成了字符串。
- JSX轉(zhuǎn)化:
- Babel轉(zhuǎn)義器會(huì)把jsx轉(zhuǎn)換成一個(gè)名為React.createElement()的方法調(diào)用。
元素渲染:
- 元素是構(gòu)成React應(yīng)用的最小單位。與瀏覽器的Dom元素不同,React當(dāng)中的元素事實(shí)上是普通的對(duì)象,ReactDOM可以確保瀏覽器DOM的數(shù)據(jù)與React元素保持一致。
- 將元素渲染到DOM中。
- 通過(guò)ReactDOM.render()的方法來(lái)將其渲染到頁(yè)面上:
- 該方法有兩個(gè)參數(shù):第一個(gè)是要渲染的React元素,第二個(gè)是要插入的DOM節(jié)點(diǎn)。
- React的元素都是不可變的,元素被創(chuàng)建之后,你是無(wú)法改變其內(nèi)容或者屬性的,一個(gè)元素好像就是動(dòng)畫里的一幀,它代表應(yīng)用界面在某一時(shí)間點(diǎn)的樣子。對(duì)于初學(xué)者來(lái)說(shuō),更新界面的唯一辦法是創(chuàng)建一個(gè)新的元素,然后將它傳入React.render()方法。
- eg
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(tick, 1000);
如下方法通過(guò)setInterval計(jì)時(shí)器每秒鐘調(diào)用一個(gè)ReactDOM.render()
注意: 在實(shí)際生產(chǎn)開發(fā)中大多數(shù)應(yīng)用只會(huì)調(diào)用一個(gè)ReactDOM.render()
-
React只會(huì)更新必要的部分。
- ReactDOM 首先會(huì)比較元素內(nèi)容先后的不同,而在渲染過(guò)程中只會(huì)更新變化的部分。如上的例子中React只改變了頁(yè)面中數(shù)字發(fā)生變化的部分。
組件&&props
概述:
- 組件可以將UI切成一些獨(dú)立的、可服用的部件,這樣你就只需要專注構(gòu)建每一個(gè)單獨(dú)的部件。從概念上看其就像是函數(shù),他可以接收任意值(稱之為“props”),并返回一個(gè)需要在頁(yè)面上展示的React元素。
組件的定義:
- 定義一個(gè)組件最簡(jiǎn)單的方式是使用Javascript函數(shù)(必須要有一個(gè)return值):
- eg:
規(guī)則:
- 無(wú)論是使用函數(shù)或是類來(lái)聲明的組件都不能修改他自己的props(列入:給props增加屬性,刪除屬性,更改屬性值)。
function Welcome() {
return <h1>Hello,{props.name}</h1>
}
// 該函數(shù)是一個(gè)有效的React組件,他接收一個(gè)單一的'props'對(duì)象并返回一個(gè)React元素。我們之所以成這種類型的組件為函數(shù)定義組件,是因?yàn)閺淖置嫔蟻?lái)看,他就是一個(gè)javascript函數(shù)。
- 我們也可以使用ES6的class來(lái)定義一個(gè)組件:
- eg
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
組件渲染
- react的元素可以是HTML元素,也可以是用戶的自定義的組件
const element = <welcome name = "Sara" />
- 當(dāng)React遇到的元素是用戶自定組件,他會(huì)將JSX屬性作為單個(gè)的對(duì)象傳遞給改組件,這個(gè)對(duì)象稱之為'props'
- eg:
function Welcome (props){
retrun <h1>Hello,{props.name</h1>
}
const element = <Welcome name = "Sara" />
ReactDOM.render(
element,
document.getElementById('root')
);
// 如上在頁(yè)面展示內(nèi)容為:Hello ,Sara
- 渲染流程:
1.我們對(duì)<Welcome name="Sara"/>元素調(diào)用了ReactDOM.render()方法。
- React將{name: 'Sara'}作為props傳入并調(diào)用Welcome組件。
- Welcome組件將<h1>Hello, Sara</h1>元素作為結(jié)果返回。
- ReactDOM將DOM更新為<h1>Hello,Sara</h1>
- 注意:組件的名稱必須以大寫字母開頭。eg:<div/>表示一個(gè)DOM標(biāo)簽,但<Welcome/>表示一個(gè)組件并限定了它的可用范圍
- 組合組件:
- 組件可以在他的輸出中引用其他組件:
組件的生命周期和狀態(tài)
應(yīng)用條件
- 組件的狀態(tài)state:與屬性非常相似,但是是私有的,完全受控于當(dāng)前組件。
- 要想使用組件的生命周期鉤子函數(shù),或者使用給組件加狀態(tài)必須以類的形式定義組件。
概述:
- 每個(gè)組件都有幾個(gè)生命周期函數(shù),以will為前綴的函數(shù)是發(fā)生在母線是之前條用,以did為前綴的是在發(fā)生某些事之后調(diào)用。
Mounting : 如下方法在組件實(shí)例被創(chuàng)建和被插入到dom中時(shí)被調(diào)用。
- constructor():
- 在組件被mounted之前調(diào)用,我們的組件繼承自React.Component,constrcutor函數(shù)中我們?cè)谄渌僮髑皯?yīng)該先調(diào)用super(props),否則this.props將會(huì)是undefined.
- constructor是初始化state的好地方。如果我們不需要初始化state,也不需要bind任何方法,那么我們的組建中不需要出現(xiàn)constructor函數(shù)。
- 注意如下情況,很容易產(chǎn)生bug,我們通常的做法是,提升state到父組件中,而不是使勁兒的同步state和props.
constructor (props){
super(props);
this.state={
color:props.initialColor
};
}
-
componentWillMount()
- 此方法在mounting之前被立即調(diào)用,他在render()之前調(diào)用,因此在此方法中setState不會(huì)觸發(fā)重新渲染。此方法是服務(wù)渲染中調(diào)用的唯一的生命周期鉤子,通常我們建議使用constructor()
-
render()
- render()方法應(yīng)該是一個(gè)純方法,級(jí)他不會(huì)修改組價(jià)的state,在每一次調(diào)用時(shí)返回同樣的結(jié)果。他不直接和瀏覽器交互,如果我們 想要交互,應(yīng)該在compentDidMount()或者其他的生命中期函數(shù)里面。
-
componentDidMount()
- 此方法在組件被mounted之后立即被調(diào)用,初始化dom接單應(yīng)該在此方法中,如果要從遠(yuǎn)程獲取數(shù)據(jù),這里是實(shí)例化網(wǎng)絡(luò)請(qǐng)求的好地方。此方法中setState會(huì)觸發(fā)組件重新渲染。
-
Updating
- props和state的改變產(chǎn)生更新。在重新渲染組件時(shí),如下的方法被調(diào)用:
- componentWillReactProps(): 一個(gè)已經(jīng)mounted的組件接受一個(gè)新的props之前,componentWillReceiveProps()被調(diào)用,如果我們需要更新state來(lái)相應(yīng)prop的更改,我們可以再此方法中比較props和nexProps并使用this.setState來(lái)更改state.
- 注意: 即使props沒(méi)有改變,React也可以調(diào)用這個(gè)方法,因此如果你只想要處理改變,請(qǐng)確保比較當(dāng)前值和下一個(gè)值。當(dāng)父組件重新渲染時(shí),可能會(huì)發(fā)生這種情況。
- React在組件mounting期間不會(huì)調(diào)用此方法,只有在一些組件的props可能被更新的時(shí)候才會(huì)調(diào)用。調(diào)用this.setState通常不會(huì)觸發(fā)發(fā)componentWillReceiveProps。
-
shouldComponentUpdate()
- 使用此方法讓React知道組件的輸出是否不受當(dāng)前state或props更改的影響。默認(rèn)行為實(shí)在每次state更改是重新渲染組件,在大多數(shù)情況下,我們應(yīng)該默認(rèn)該行為。 當(dāng)接收到新的props或state時(shí),shouldComponentUpdate()在渲染之前被調(diào)用。默認(rèn)返回true,對(duì)于初始渲染或者使用forceUpdate()時(shí),不調(diào)用此方法。返回false不會(huì)阻止子組件的state更改時(shí),該子組件的重新渲染。
-
componentWillUpdate()
- 當(dāng)接收新的props或state時(shí),componentWillUpdate()在組件渲染之前被立即調(diào)用。使用此函數(shù)作為更新方程之前執(zhí)行準(zhǔn)備的機(jī)會(huì)。初始渲染不會(huì)不調(diào)用此方法。
- 注意:這里不能調(diào)用this.setState(),如果調(diào)用了會(huì)產(chǎn)生死循環(huán),一只更新。
組件的生命周期和狀態(tài)簡(jiǎn)述:(總共10個(gè)api)
實(shí)例化
- getDefaultProps
作用于組件類,只調(diào)用一次,返回對(duì)象用于設(shè)置的默認(rèn)props,對(duì)于引用值,會(huì)在實(shí)例中共享。 - getInitialState
作用于組件的實(shí)例,在實(shí)例創(chuàng)建時(shí)調(diào)用一次,用于初始化每個(gè)state,此時(shí)可以訪問(wèn)this.props。 - componentWillMount
在首次完成渲染之前條用,此時(shí)仍可以修改組件的state. - render
比選方法,創(chuàng)建虛擬DOM,該方法具有特殊的規(guī)則:- 只能通過(guò)this.props和this.state訪問(wèn)數(shù)據(jù)。
- 可以返回null,false或者任何React組件(返回React組件時(shí),必須要有一個(gè)根元素)。
- 只能出現(xiàn)一個(gè)頂級(jí)組件(不能返回?cái)?shù)組)
- 不能改變組件的狀態(tài)。
- 不能改DOM的輸出。
- componentDidMount
正式DOM被渲染出來(lái)之后調(diào)用,在方法中可以通過(guò)this.getDOMNode()訪問(wèn)到真實(shí)的DOM元素。此時(shí)可以使用其他累出來(lái)操作這個(gè)DOM。在服務(wù)端中,改方法不會(huì)被調(diào)用。
存在期
- componentWillReceiveProps
組件接收到props時(shí)調(diào)用,并將其作為參數(shù)nextProps使用,此時(shí)可以更改組件的props及state.
componentWillReceiveProps:function(nextProps){
if(nextProps.bool){
this.setState({
bool: true
});
}
}
- shouldComponentUpdate
組件是否應(yīng)當(dāng)渲染新的Props或者state,返回false表示跳過(guò)后續(xù)生命周期方法,通常不需要使用以避免出現(xiàn)bug。在出現(xiàn)瓶頸時(shí),可以通過(guò)該方法進(jìn)行適當(dāng)?shù)膬?yōu)化。 - componentDidUpdate
完成渲染新的props或者state后調(diào)用,此時(shí)可以訪問(wèn)到新的DOM元素。 - componentWillUnmount
組件被移除之前被調(diào)用,可以用于做一些清理工作,在componentDidMount方法中添加的所有任務(wù)都需要在該方法中撤銷,比如創(chuàng)建的定時(shí)器或添加的事件監(jiān)聽器。
state與props的區(qū)別:
state的作用:
- state是React中組件的一個(gè)對(duì)象。React把用胡界面當(dāng)做是狀態(tài)機(jī),想象他又不同的狀態(tài),然后渲染這些狀態(tài),可以輕松的讓用戶界面與數(shù)據(jù)保持一致。
- react中,更新組建的state最導(dǎo)致重新渲染用戶界面(不要操作DOM),簡(jiǎn)言之:就是用戶界面會(huì)隨著state變化而變化。
state工作原理:
- 常用的通知React數(shù)據(jù)變化的方法是調(diào)用setState(data,callback).這個(gè)方法。這個(gè)方法會(huì)合并data到this.state,并重新渲染組件。渲染完成后,調(diào)用可選的callback,大部分情況不需要提供callback,因?yàn)镽eact會(huì)負(fù)責(zé)吧界面更新到最新狀態(tài)。
應(yīng)用場(chǎng)景:
- 大部分組件的工作原理應(yīng)該是從props里取數(shù)據(jù)并渲染出來(lái)。但是,有時(shí)需要對(duì)用戶的輸入,服務(wù)器請(qǐng)求或者時(shí)間變化做出響應(yīng),這是才需要state.
- 組件應(yīng)該盡可能的無(wú)狀態(tài),這樣能隔離state.把他放到最合理的地方(Redus做的就是這個(gè)事情),也能減少冗余并易于解釋程序運(yùn)作過(guò)程。
- 常用的模式就是創(chuàng)建多個(gè)只負(fù)責(zé)渲染數(shù)據(jù)的無(wú)狀態(tài)(stateless)組件,在他們的上層創(chuàng)建一個(gè)有狀態(tài)(statefull)組件并把它的狀態(tài)通過(guò)props傳遞給子級(jí),有狀態(tài)的組件封裝了所有的用戶交互邏輯,而這些無(wú)狀態(tài)組件只負(fù)責(zé)聲明是的渲染數(shù)據(jù)。
那些應(yīng)該作為state
- state應(yīng)該包括那些可能被組件的事件處理器改變并觸發(fā)用戶界面更新的數(shù)據(jù)。中數(shù)據(jù)一般很小且能被JSON序列化
條件渲染:
- React中的條件渲染和javascript中的一致,使用javascript操作符if或者條件運(yùn)算符來(lái)創(chuàng)建當(dāng)前的元素,然后讓React根據(jù)他們來(lái)更新UI。
function UseGreeting(props){
return <h1>Welcome back!</h1>
}
function GuestGreeting(props){
return <h1>Please sign up.</h1>
}
// 創(chuàng)建一個(gè)條件渲染組件。
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
// Try changing to isLoggedIn={true}:
<Greeting isLoggedIn={false} />,
document.getElementById('root')
);
- 元素變量:可以使用變量來(lái)存儲(chǔ)元素。他可以幫助你有條件的渲染組件的一部分,兒輸出的其他部分不會(huì)改變。
//新建兩個(gè)無(wú)狀態(tài)組件
function LoginButton(props) {
return (
<button onClick={props.onClick}>
Login
</button>
);
}
function LogoutButton(props) {
return (
<button onClick={props.onClick}>
Logout
</button>
);
}
/// 創(chuàng)建一個(gè)有狀態(tài)組件。
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
handleLoginClick() {
this.setState({isLoggedIn: true});
}
handleLogoutClick() {
this.setState({isLoggedIn: false});
}
render() {
const isLoggedIn = this.state.isLoggedIn;
let button = null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
- 與運(yùn)算符 &&
可以通過(guò)用花括號(hào)包裹代碼在JSX中嵌入任何表達(dá)式,也包括javascript的邏輯&&,他可以方便的條件渲染一個(gè)元素。
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
);
}
const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
<Mailbox unreadMessages={messages} />,
document.getElementById('root')
);
- 三目運(yùn)算符:條件渲染的另一種方法是使用javascript的條件運(yùn)算符:condition?true:false
eg1:
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>
);
}
eg2:
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn ? (
<LogoutButton onClick={this.handleLogoutClick} />
) : (
<LoginButton onClick={this.handleLoginClick} />
)}
</div>
);
}
- 阻止組件渲染:在極少數(shù)的情況下,你可能希望隱藏組件,即使他被其他組件渲染。讓render方法返回null而不是他的渲染結(jié)果即可實(shí)現(xiàn)。
function (!props.warn){
return null
}
return (
<div className = "warning">
Warning!
</div>
)
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {showWarning: true}
this.handleToggleClick = this.handleToggleClick.bind(this);
}
handleToggleClick() {
this.setState(prevState => ({
showWarning: !prevState.showWarning
}));
}
render() {
return (
<div>
<WarningBanner warn={this.state.showWarning} />
<button onClick={this.handleToggleClick}>
{this.state.showWarning ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('root')
);
列表&keys
- 渲染多個(gè)組件:
可以通過(guò)使用{}在JSX內(nèi)構(gòu)件一個(gè)元素集合
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
// 把整個(gè)listItems插入到ul元素中,然后渲染DOM:
ReactDOM.render(
<ul>{listItems}</ul>
document.getElementById('root')
);
- 基礎(chǔ)列表組件:
通常你需要渲染一個(gè)列表到組件中
function NumberList(props){
const number = props.number;
const listItems = number.map((number)=>{
<li>{number}</li>
});
return (
<ul>{listItems}</ul>
)
}
const numbers = [1,2,3,4,5];
ReactDOM.render(
<NumberList number = {numbers} />
document.getElementById('root')
) ;
- keys
keys可以在DOM中的木屑元素被增減或者刪除的時(shí)候幫助React識(shí)別哪些元素發(fā)生了變化。因此你應(yīng)當(dāng)給數(shù)組中的每一個(gè)元素富裕一個(gè)明確的標(biāo)識(shí)。一個(gè)元素的key最好是這個(gè)元素在列表中擁有的一個(gè)獨(dú)一無(wú)二的字符串。通常,我們使用來(lái)自數(shù)據(jù)的id作為元素的key,當(dāng)元素沒(méi)有確定的ID時(shí),你可以使用他的序列號(hào)索引index作為key