React 從青銅到王者系列教程之倔強青銅篇
前端大陸乃是技術界近年來新興起的板塊,隨著人們對網站交互和性能越來越高, 前往前端大陸修鍊 Javascript 的召喚師如過江之鯽,數不勝數,前端奇人異士之多,故修鍊之法林林總總,俱不相同, Web 前端的未來尚無定論,內部卻已起了門戶之見, 幸而前端圈核心門派正道大昌,人氣鼎盛,其中尤以 React、Vue、Angular 為三大支柱,是為領袖,今天的故事,便是從 React 峽谷開始的
React 峽谷的每個前端召喚師,根據對 React 技術棧 和前端的理解,分別是青銅,白銀,黃金,鉑金,鑽石,星耀和王者段位,也對應這這個系列教程的七個模塊
- 倔強青銅
- 初入峽谷的初始段位,默認召喚師已經有了
ES6
,nodejs
的基礎 - 使用
create-react-app
建立React
開發環境 - 學習
React
世界裡的基本玩法,例如組件化,JSX
,事件監聽,內部state
,組件的props
、生命周期函數等 - 這篇文章主要介紹
React
青銅升白銀需要的基礎知識,看完你就白銀啦
- 秩序白銀
- 到了白銀段位,基本都是有了基本的操作,不會出現呆萌的站在地方塔下被打死的情況了
- 我們需要買一個皮膚來提升頁面美觀並且多加練習
- 學習使用螞蟻金服
ant-design
的使用
- 榮耀黃金
- 到了這個階段,召喚師對
React
有了基本的認識,想進一步的提升段位,我們需要提高自己的大局觀 - 學習使用
React-Router4
來讓我們有多面作戰能力 - 學會使用
BrowserRouter
,Router
,Link
等組件 - 學會使用
Redux
和隊友配合,修鍊大局觀 - 了解單項數據流開發模式和
Redux
的各種概念,如dispatch
,action
,reducers
- 使用
react-redux
更好的和Redux
配合有大局觀意識,上鉑金也是很 easy 了
- 尊貴鉑金
- 很多召喚師卡在鉑金上不去,因為鉑金想上鑽石,需要了解更多的細節和原理
React
原理剖析- 對自己技能的原理有深刻的了解,上鑽石必備
- 永恆鑽石
- 鑽石段位開始了徵兆模式,召喚師的技能池要足夠深才能更進一步,對自己擅長技能的理解也要更深刻
Redux
中間件機制,實現自己的中間件- 常見的React 性能優化方式
- 服務端渲染
Redux
之外其他的數據解決方案如mobx
,dva
- 至尊星耀
- 這個段位已經是獨當一面的強者了,目標僅限於 React 這個庫很難更近一層,需要了解更底層的原理
Redux
原理剖析+實現自己的Redux
React-Router
+實現自己的React-Router
Webppack
工作機制和原理剖析Babel
工作機制和原理剖析
- 最強王者
- 達到最強王者已經是頂尖召喚師,在整個 React 峽谷都是鼎鼎大名的存在,聽說上面還有傳說中的榮耀王者的段位,我這輩子是達不到了,也沒法教你們了,囧
- 這個階段,我只推薦《程序員健康指南》一本書,保持身心健康,成為榮耀王者是早晚的事
下面開始我們的正文,倔強青銅篇目錄
- 環境搭建
- 第一個組件
- 組件嵌套和屬性傳遞
- 狀態處理
- 生命周期
環境搭建
默認大家已經有 node 環境了,先安裝腳手架
npm install create-react-app -g
然後建立項目,並啟動
create-react-app bronzecd bronzenpm start
看到下面的圖,意味著第一個React
應用已經啟動起來了
我們打開 src 目錄
src├── App.css├── App.js├── App.test.js├── index.css├── index.js├── logo.svg└── registerServiceWorker.js
index.js
是入口文件,核心內容就是分別引入React
和ReactDom
,然後渲染了一個組件App
在#root
這個元素上
import React from "react";import ReactDOM from "react-dom";import App from "./App";ReactDOM.render(<App />,document.getElementById("root"));
然後重點看下App.js
是我們組件的具體內容
import React, { Component } from "react"class App extends Component { render() { return ( <div className="App"> <p> To get started, edit <code>src/App.js</code> and save to reload. </p> </div> ); }}export default App;
這個基本上是最簡單的React
組件了,自己實現組件也是分這麼幾個步驟
import React
- 新建一個類,繼承
React.Component
,React
里每個組件都可以寫成一個類 - 類的
render
函數返回值,就是顯示在頁面的內容 render
里返回的是東西有點詭異,表面上是html
其實Babel
會把JSX
轉成React.createElememt
來執行- 由於
JSX
本質就是 js,class
是 js 的關鍵字,所以要用className
代替 - 如果想在
JSX
里渲染變數,使用{}
包裹即可
現在[Babel官網]](http://babeljs.io/repl/),看下JSX
編譯後的代碼,再划下重點,所謂的JSX
,其實就是js 對象,再用ReactDom.render
方法,渲染成dom
// jsx<div className="App"> <p>hello react</p></div>// 轉換後React.createElement( "div", { className: "App" }, React.createElement( "p", null, "hello react" ))
第一個組件
我們實現自己的第一個組件,修改App.js
為
import React, { Component } from "react"class App extends Component { render() { const level="最強王者" return ( <div> <h2>我們的目標是{level}</h2> </div> ) }}export default App
由於JSX
本質上其實就是 js,所以我們可以在{}
裡面使用 js 的表達式等功能,比如三元、函數、變數等等,還可以把數組映射為列表,我們把代碼修改為
import React, { Component } from "react"class App extends Component { render() { const level="最強王者" const isKing = true const title = isKing ? <p>早睡早起,理性遊戲</p> : <h2>我們的目標是{level}</h2> const wordList = ["俺老孫來也","有妖氣","取經之路,就在腳下"] return ( <div> {title} {isKing ? <p>我就是王者</p>: null} <ul> {wordList.map(v=><li key={v}>{v}</li>)} </ul> </div> ) }}export default App
這裡要稍微注意一點,就是render
里,如果return
多個元素,必須有一個父元素包裹,否則會有個報錯
我們在return 之外把JSX
複製給變數,JSX
里也可以在{}
內部使用三元表達式,大家可以修改isKing
是false
試一試
然後就是渲染列表,我們使用map
函數直接映射為JSX
的數組,記得列表裡每個元素都有一個key
屬性,關於它的作用,我們講虛擬dom 的時候會介紹
組件嵌套和屬性傳遞
如果我們繼續設計我們的應用,現在再設計一個Tank
組件,可以直接放在App
里使用,並且可以傳遞一個屬性,在組件內部,使用this.props.key
獲取
import React, { Component } from "react"class App extends Component { render() { const level="最強王者" const isKing = true const title = isKing ? <p>早睡早起,理性遊戲</p> : <h2>我們的目標是{level}</h2> return ( <div> {title} {isKing ? <p>我就是王者</p>: null} <Tank name="程咬金"></Tank> </div> ) }}class Tank extends Component { render() { return ( <div> <h3>{this.props.name}是一個坦克</h3> </div> ) }}export default App
如果我們的組件只有一個render
方法,還可以寫成一個函數,props 是函數的參數,我們稱呼這種組件為無狀態組件,這種組件的特點,就是返回只和 props 有關,復用性高
function Tank(props){ return ( <div> <h3>{props.name}是一個坦克</h3> </div> )}
這樣我們就可以把應用分成多個組件,然後用拼積木的形式拼接應用,但是現在的組件都沒法變化,下一步,我們學習 React 的狀態管理,也就是 state
React 狀態管理和事件監聽
我們通過在構造函數constructor里初始 state,其實就是一個普通的 js 對象,然後可以調用 this.setState函數修改 state,每次 setState,都會重新渲染組件 組件里可以使用 onClick來綁定一個函數,可以監聽用戶的事件,話不多說看代碼
class App extends Component { constructor(props){ super(props) this.state = { isKing:true } this.handleClick = this.handleClick.bind(this) } handleClick(){ this.setState({ isKing: !this.state.isKing }) } render() { const level="最強王者" const title = this.state.isKing ? <p>早睡早起,理性遊戲</p> : <h2>我們的目標是{level}</h2> return ( <div> <button onClick={this.handleClick}>點我</button> {title} {this.state.isKing ? <p>我就是王者</p>: null} <Tank name="程咬金"></Tank> </div> ) }}
我們需要關注的點,一個是constructor
,我們稱之為構造函數,組件初始化狀態放在這裡,設置了isKing
是true
,然後button
元素上的onClick
的時候,執行handleClick
,在handleClick
內部,調用this.setState
來修改isKing
constructor
函數里的bind
是強行把handleClick
的this
綁定在組件上,否則onClick
的時候會獲取this
引用出錯,解決這個問題還有其他的形式,可以不用寫bind
這一行
import React, { Component } from "react"class App extends Component { constructor(props){ super(props) this.state = { isKing:true } this.handleClick = this.handleClick.bind(this) } // 在constructor裏手動 bind handleClick(){ this.setState({ isKing: !this.state.isKing }) } // 綁定的時候傳遞箭頭函數 handleClick1(){ this.handleClick() } // 定義的時候是剪頭函數 handleClick2 = ()=>{ this.handleClick() } // onClick 的時候直接綁定 handleClick3(){ this.handleClick() } render() { const level="最強王者" const title = this.state.isKing ? <p>早睡早起,理性遊戲</p> : <h2>我們的目標是{level}</h2> return ( <div> <button onClick={this.handleClick}>點我</button> <button onClick={()=>this.handleClick1()}>點我1</button> <button onClick={this.handleClick2}>點我2</button> <button onClick={this.handleClick3.bind(this)}>點我3</button> {title} {this.state.isKing ? <p>我就是王者</p>: null} <Tank name="程咬金"></Tank> </div> ) }}
生命周期
最後要介紹的,就是React
組件的生命周期,每個組件在不同的時期,會有不同的鉤子函數執行,比如組件載入完畢後,會執行componentDidMount
鉤子函數
class App extends Component{ componentDidMount(){ console.log("組件渲染完畢") } render(){ console.log("組件正在渲染") return <h2>倔強青銅</h2> }}// 組件正在渲染// 組件渲染完畢
React
在不同的階段,會執行不同的函數,我從網上找了個圖,很清晰的說明各個生命周期函數執行的時機,
class App extends Component { constructor(props){ super(props) this.state = { isKing:true } this.handleClick = this.handleClick.bind(this) console.log("constructor App 的構造函數,初始化先執行") } handleClick(){ this.setState({ isKing: !this.state.isKing }) } componentWillMount(){ console.log("componentWillMount,組件 App 準備渲染") } componentDidMount(){ console.log("componentDidMount,組件 App 渲染完畢") } shouldComponentUpdate(){ console.log("shouldComponentUpdate,判斷 App 組件是否應該渲染, 默認返回 true") return true } componentWillUpdate(){ console.log("componentWillUpdate,組件 App 準備更新了") } componentDidUpdate(){ console.log("componentDidUpdate, 組件 App 更新完畢了") } render() { const level="最強王者" const title = this.state.isKing ? <p>早睡早起,理性遊戲</p> : <h2>我們的目標是{level}</h2> const wordList = ["俺老孫來也","有妖氣","取經之路,就在腳下"] console.log("組件 App 正在渲染") return ( <div> <button onClick={this.handleClick}>點我</button> {title} {this.state.isKing ? <p>我就是王者</p>: null} <ul> {wordList.map(v=><li key={v}>{v}</li>)} </ul> <Tank name="程咬金"></Tank> </div> ) }}// 首次載入列印constructor App 的構造函數,初始化先執行componentWillMount,組件 App 準備渲染組件 App 正在渲染componentDidMount,組件 App 渲染完畢// 點擊按鈕修改狀態時列印shouldComponentUpdate,判斷 App 組件是否應該渲染, 默認返回 truecomponentWillUpdate,組件 App 準備更新了組件 App 正在渲染componentDidUpdate, 組件 App 更新完畢了
除了上面介紹的,還有需要注意的
React16
新增的componentDidCatch
生命周期,用來處理報錯shouldComponentUpdate
返回false
,那麼組件就不會渲染- 如果是子組件,還有個
componentWillReceiveProps
- 組件卸載有
componentWillUnmount
,用來做資源的清理 - 合理利用生命周期,在不同的階段做不同的事情 如果你能看到這裡,那真的對
React
是真愛,恭喜你,你已經是秩序白銀啦,領取徽章
今天的代碼都在github
下期預告:秩序白銀篇-- 使用ant-designUI庫,有問題留言,我們還可以開黑,一起上王者
推薦閱讀:
※如何評價React VR Project?
※為什麼 GUI 編程中,Web 平台的技術革新特別火爆,而 Android 和 iOS 沒什麼成果?
※知乎是否會停止使用React?
※關於在react中request到底是應該寫在哪裡?
※怎麼樣理解reactjs中組件的反模式?
TAG:React |