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