前言:
終于結(jié)束了緊張的一個學(xué)期梢卸,網(wǎng)課上的挺有趣蛤高,就是課程太擠了點。這個暑假塞绿,就從React開始吧异吻。
一诀浪、為什么學(xué)習(xí)React雷猪?
首先求摇,React殊者、Vue幽污、Angular合稱當(dāng)前前端最為流行的三大框架距误,就是前端的三大將吧准潭。而國內(nèi)因為Angular相對其他兩者來說不是很受歡迎刑然,前面4月份的時候我是先學(xué)習(xí)了Vue的泼掠,由于國內(nèi)Vue和React的使用都是很多的,所以肯定都是要學(xué)習(xí)的挡逼。React是facebook于2013年開源的JS框架家坎,在HackerRank一份關(guān)于2020年最想要學(xué)習(xí)的框架中React是排名第一的虱疏。
二做瞪、邂逅React開發(fā)
React和Vue一樣都是聲明式的編程范式穿扳,這在我學(xué)習(xí)Vue的時候就嘗到了甜頭国旷,這種編程范式相對于傳統(tǒng)使用jQuery的命令式編程來說跪但,最大的區(qū)別就是將變量交給Dom元素來展示之后屡久,不管是發(fā)生了什么被环,如果想要頁面進行實時變化的話,修改那個變量的值就好了浸锨,不需要再拿到這個Dom元素然后進行重新的掛載相應(yīng)的數(shù)據(jù)柱搜。
下面通過一個案例分別使用原生和React進行實現(xiàn)來邂逅一下React的開發(fā)聪蘸。
就是這么一個案例控乾,一開始顯示Hello World阱持,點擊之后顯示Hello React
原生實現(xiàn)
<h2 class="text"></h2>
<button class="btn">改變文本</button>
<script>
//文本
let message = "Hello World!!!";
//拿到文本元素
const textElt = document.getElementsByClassName("text")[0];
//拿到按鈕元素
const btnElt = document.getElementsByClassName("btn")[0];
//設(shè)置文本內(nèi)容
textElt.innerHTML = message;
//添加監(jiān)聽事件
btnElt.addEventListener("click",e=>{
//打印點擊信息
// console.log("點擊了文本");
message = "Hello React!!!";
textElt.innerHTML = message;
})
</script>
不管是原生也好衷咽,jQuery也好镶骗,在掛載的數(shù)據(jù)想要進行改變的時候鼎姊,都需要拿到那個Dom元素相寇,然后進行數(shù)據(jù)的修改钮科,而且設(shè)置和修改時進行的步驟是一樣的绵脯,就是重新設(shè)置了一次。
React閃亮登場
添加依賴
使用一個框架赃承,第一件事情肯定是添加依賴啦瞧剖,不同于Vue筒繁,React需要添加三個庫才能進行開發(fā)巴元。這也是React功能的多元性所引起的逮刨,業(yè)務(wù)多元也就意味著體量得越大,React在0.14版本之前沒有react-dom這個概念恢总。由于擴展了移動端的業(yè)務(wù)片仿,出現(xiàn)了React-native砂豌,所以為了分離web端和移動端開發(fā)的依賴光督,將它們共有的核心代碼放在React包中结借。而react-dom在web端和移動端完成的事情不同,在web端react-dom將jsx語法渲染成真實DOM顯示在瀏覽器中咖熟,移動端則是將jsx渲染成Android或者ios的原生控件馍管。
除了React和React-dom之外呢還需要添加一個庫咽斧,那就是Babel张惹。這個之前接觸過了岭洲,在使用ES6語法的時候就需要通過Babel給它轉(zhuǎn)成大多數(shù)瀏覽器所支持的ES5語法。而在React中其實默認下是可以不適用Babel的雷激,但是不使用Babel就需要通過React.createElement這種方式來進行React開發(fā)屎暇,代碼就非常的繁瑣并且可讀性很差根悼。而解決這種繁瑣的編寫方式的方法是使用JSX(JavaScript XML)語法進行開發(fā)挤巡,但是React默認是不能認識這種方式的矿卑,所以就要靠babel給轉(zhuǎn)成React.createElement這種方式母廷。
引入這三個庫
<!-- 通過CDN引入React依賴 -->
<!--
為什么使用crossorigin屬性?
因為crossorigin屬性使得我們能夠接收到跨域的腳本錯誤消息苔悦,
然后打印在控制臺玖详,從CDN上引入的腳本是跨域的勤讽。
-->
<!-- React核心庫 -->
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<!-- React-Dom庫 -->
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- babel庫向臀,將jsx語法轉(zhuǎn)換成render.createElement這種方式 -->
<!-- 你可以在任何 <script> 標簽內(nèi)使用 JSX诸狭,方法是在為其添加 type="text/babel" 屬性。-->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
初識React
<div>Header</div>
<div id="app">app</div>
<div>Footer</div>
<!-- 使用React來管理app的文本內(nèi)容 -->
<!-- 注意:為了讓babel解析JSX語法芹彬,也就是下面render函數(shù)中的第一個參數(shù)舒帮,
必須在script標簽這里添加一個屬性玩郊,type="text/babel" -->
<script type="text/babel">
let message = "hello world";
// ReactDom.render(渲染內(nèi)容,掛載元素);渲染的內(nèi)容可以是HTML元素译红,也可以是React組件
ReactDOM.render(<h2>{message}</h2>,document.getElementById("app"));
</script>
<!--
React的語法和Vue還是挺大不同的临庇,Vue是直接New一個對象,然后掛載到某個元素上(使用el時),而React這里
是直接使用一個庫中導(dǎo)出的對象已卷,然后用它的一個render函數(shù)
淳蔼。而且React中取變量數(shù)據(jù)的語法是{}一個單花括號讳癌,而Vue中使用的是雙花括號{{mustache}}語法
Vue中是這樣來開發(fā)
<div id="app">
{{message}}
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
</script>
-->
現(xiàn)在就能夠?qū)essage的內(nèi)容在瀏覽器中進行一個顯示了晌坤,接下來就是實現(xiàn)上面的案例骤菠。
React案例實現(xiàn)
ReactDOM.render(
<h2>{message}</h2>
<button>改變文本</button>,//JSX語法這里根標簽是只能有一個的商乎,這里就和Vue相同
//Vue在定義組件的時候也是只能有一個根標簽
//我上面這個打出來就報錯了
document.getElementById("app")
)
這樣子就正確了
<script type="text/babel">
let message = "Hello world!!!";
function btnClick(){
//測試是否確實能夠激發(fā)點擊事件處理函數(shù)
console.log("the button is clicked");
message = "Hello React!!!";
//打印message
console.log(message);
/*
對于Vue來說鹉戚,如果message改變了抹凳,那么頁面也會做出實時的響應(yīng)
對頁面UI進行修改却桶,這里就測試React是不是也能這樣
*/
}
ReactDOM.render(
<div>
<h2>{message}</h2>
<button onClick={btnClick}>改變文本</button>
</div>,
document.getElementById("app")
)
//在執(zhí)行了這個render函數(shù)之后颖系,app這個元素里面包含的內(nèi)容將會被這里render函數(shù)的第一個參數(shù)完全替換
//這一點和Vue也是一樣的
</script>
經(jīng)過實測嘁扼,確實在這里react和vue是不同的趁啸。在這里不傅,如果想要UI進行重新渲染,我們就需要進行再一次的render函數(shù)商虐,就是重復(fù)的工作在做一遍秘车,一開始怎么掛載上去數(shù)據(jù)的叮趴,再掛載一次就實現(xiàn)了UI的變化眯亦。
<div id="app">
<h2>this is app</h2>
</div>
<!-- jsx語法不能像這樣寫 -->
<button onClick="btnClick();">改變文本</button>
<script type="text/babel">
let message = "Hello world!!!";
function btnClick(){
//測試是否確實能夠激發(fā)點擊事件處理函數(shù)
console.log("the button is clicked");
message = "Hello React!!!";
//打印message
console.log(message);
/*
對于Vue來說搔驼,如果message改變了,那么頁面也會做出實時的響應(yīng)
對頁面UI進行修改扔字,這里就測試React是不是也能這樣
*/
render();
}
function render(){
/*
<button onClick="window.alert('hello');">改變文本</button>jsx這里和原先的html還不一樣
事件句柄后面是不能直接添加雙引號括起來的js代碼的,必須要將這些js代碼封裝在一個函數(shù)中扭粱,然后
通過{}語法來引用這個函數(shù)
*/
ReactDOM.render(
<div>
<h2>{message}</h2>
<button onClick={btnClick}>改變文本</button>
</div>,
document.getElementById("app")
)
//在執(zhí)行了這個render函數(shù)之后琢蛤,app這個元素里面包含的內(nèi)容將會被這里render函數(shù)的第一個參數(shù)完全替換
//這一點和Vue也是一樣的
}
render();
</script>
案例確實是實現(xiàn)了,但是這其實不是我們想要的那種抛虏,因為還是像是命令式編程范式那樣進行編程博其,我們想要的應(yīng)該是message修改了,不需要我們進行操作UI就進行實時的更新的那種迂猴,那才是聲明式編程慕淡。
三、React組件化開發(fā)
想要實現(xiàn)我們上面的那種要求就需要進行組件化開發(fā)了沸毁,由于只是邂逅React開發(fā)峰髓,所以我們就先從一種組件化開發(fā)的方式進行入手傻寂。
初識React組件化
錯誤示范案例:
<div id="app"></div>
<script type="text/babel">
//通過React組件化的方式來實現(xiàn)上面的文本案例
//ReactDOM.render(HTML標簽|React組件,掛載的元素)
//React如何來定義和使用組件呢,這里介紹第一種携兵,聲明類繼承React.Components這種定義組件的方式
//定義組件
class App extends React.Component{
constructor(){
super();/*這是必須的疾掰,如果我們不寫這里會有默認的實現(xiàn),
但是我們一當(dāng)覆蓋了constructor函數(shù)凛虽,我們就
必須手動加上這一句*/
this.message = "Hello world~~~";
}
//組件名首字母要大寫,為了和HTML標簽進行區(qū)分
//組件如何告訴ReactDom.render函數(shù)需要渲染什么內(nèi)容呢?
//答案是定義一個render函數(shù),然后返回你想要渲染的內(nèi)容,一定是render函數(shù)哈
render(){
/*將文本內(nèi)容抽離到成員變量中草戈,然后監(jiān)聽按鈕的點擊涨颜。
發(fā)生了點擊后就改變變量的內(nèi)容见擦,講道理這樣就可以實時改變UI了*/
return (
<div>
<h2>{this.message}</h2>
<button onClick={this.btnClick.bind(this)}>改變文本</button>
</div>
)
}
btnClick(){
// console.log("this button is clicked~~~~");
//講道理,這里修改成員變量就闊以完成案例了
this.message = "Hello React~~~";//啊這里不行啊肪凛,這里的this顯示是undefined
/*
我們這個btnClick是在啥時候調(diào)用的戳葵?
是在button點擊后戏自,在它的事件處理函數(shù)中去回調(diào)這個這個函數(shù)见芹,在onClick內(nèi)部
是通過btnClick.apply(undefined)的方式去回調(diào)的缨睡,所以這里的this就給綁定了
undefined
解決方法:在事件句柄那里傳入回調(diào)函數(shù)的時候通過bind給他綁定上一個this怕午,
bind(obj){
return function() {
return func.apply(obj, arguments);
}
}
bind內(nèi)部類似做了一個這種操作羽戒,返回的這個函數(shù)在執(zhí)行的時候就算是又使用
apply放入了一個undefined也是無濟于事的包蓝,綁定的都是我們希望的this
其實在開發(fā)中this是非常靈活的硅瞧,所以為了以防以后亂掉坑四苇,不知道this到底指向哪里
建議去看coderwhy老師在公眾號發(fā)布的this的一篇文章
https://mp.weixin.qq.com/s/hYm0JgBI25grNG_2sCRlTA
*/
console.log(this.message);
/*OK榆骚,到這里我們就能夠改變了成員變量message了碉钠,但是你會發(fā)現(xiàn)污筷,雖然成員變量確實是進行了改變了揪惦,
但是畫面完全沒發(fā)生改變诊县,然后你猛的一驚胸嘁,一拍大腿想到诬辈,對哦,React中改變了掛載的數(shù)據(jù)是要進行再
次的刷新的Render的秘蛔,但是挺尷尬叠赐,需要再次的是下面的ReactDOM.render而不是我們組件中的render
惹苗,這根本調(diào)不到咋辦呢儡首?其實啊鹅髓,正如我們之前想要的一樣,雖然底層確實要再次render错蝴,但是我們不
希望是由我們自己來調(diào)用,就跟每個女孩紙都希望自己不說男朋友都能知道自己在想啥一樣玛界。而React就
有這么種機制,約法三章馅精,嗯嗯,建議每個女孩紙也和你的那個Ta約法三章壮不,這樣他才能知道自己有時候
錯在哪了*/
}
}
ReactDOM.render(<App/>,document.getElementById("app"));
</script>
正確的案例實現(xiàn)
<script type="text/babel">
class App extends React.Component{
constructor(){
super();
//React說,好吧褪贵,今天咱來約法三章躲庄,你將掛載的數(shù)據(jù)丟到state里來。這樣你要是想要改變數(shù)據(jù)了
//請通過setState來改效扫,知會我一聲兒倔监,我就給你把UI給刷新一遍。咦菌仁,這有點像Vue中那個分發(fā)事件
//進行狀態(tài)維護那種感覺了浩习。
this.state = {
message:"Hello world~~~"
}
}
render(){
//這個事件處理函數(shù)一定要一直bind(this),不然下面都找不到this.setState
return (
<div>
<h2>{this.state.message}</h2>
<button onClick={this.btnClick.bind(this)}>改變文本</button>
</div>
)
}
btnClick(){
this.setState({
message:"Hello React~~~"
})
}
}
ReactDOM.render(<App/>,document.getElementById("app"));
</script>
這樣就實現(xiàn)了掘托,修改成員變量然后UI實時改變咯。