標籤:

React 從青銅到王者系列教程之倔強青銅篇

前端大陸乃是技術界近年來新興起的板塊,隨著人們對網站交互和性能越來越高, 前往前端大陸修鍊 Javascript 的召喚師如過江之鯽,數不勝數,前端奇人異士之多,故修鍊之法林林總總,俱不相同, Web 前端的未來尚無定論,內部卻已起了門戶之見, 幸而前端圈核心門派正道大昌,人氣鼎盛,其中尤以 React、Vue、Angular 為三大支柱,是為領袖,今天的故事,便是從 React 峽谷開始的

React 峽谷的每個前端召喚師,根據對 React 技術棧 和前端的理解,分別是青銅,白銀,黃金,鉑金,鑽石,星耀和王者段位,也對應這這個系列教程的七個模塊

  1. 倔強青銅
  • 初入峽谷的初始段位,默認召喚師已經有了ES6nodejs的基礎
  • 使用create-react-app建立React開發環境
  • 學習React世界裡的基本玩法,例如組件化,JSX,事件監聽,內部state,組件的props、生命周期函數等
  • 這篇文章主要介紹React青銅升白銀需要的基礎知識,看完你就白銀啦
  1. 秩序白銀
  • 到了白銀段位,基本都是有了基本的操作,不會出現呆萌的站在地方塔下被打死的情況了
  • 我們需要買一個皮膚來提升頁面美觀並且多加練習
  • 學習使用螞蟻金服ant-design的使用
  1. 榮耀黃金
  • 到了這個階段,召喚師對React有了基本的認識,想進一步的提升段位,我們需要提高自己的大局觀
  • 學習使用React-Router4來讓我們有多面作戰能力
  • 學會使用BrowserRouterRouterLink等組件
  • 學會使用Redux和隊友配合,修鍊大局觀
  • 了解單項數據流開發模式和Redux的各種概念,如dispatch,action,reducers
  • 使用react-redux更好的和Redux配合有大局觀意識,上鉑金也是很 easy 了
  1. 尊貴鉑金
  • 很多召喚師卡在鉑金上不去,因為鉑金想上鑽石,需要了解更多的細節和原理
  • React原理剖析
  • 對自己技能的原理有深刻的了解,上鑽石必備
  1. 永恆鑽石
  • 鑽石段位開始了徵兆模式,召喚師的技能池要足夠深才能更進一步,對自己擅長技能的理解也要更深刻
  • Redux中間件機制,實現自己的中間件
  • 常見的React 性能優化方式
  • 服務端渲染
  • Redux之外其他的數據解決方案如mobxdva
  1. 至尊星耀
  • 這個段位已經是獨當一面的強者了,目標僅限於 React 這個庫很難更近一層,需要了解更底層的原理
  • Redux原理剖析+實現自己的Redux
  • React-Router+實現自己的React-Router
  • Webppack工作機制和原理剖析
  • Babel工作機制和原理剖析
  1. 最強王者
  • 達到最強王者已經是頂尖召喚師,在整個 React 峽谷都是鼎鼎大名的存在,聽說上面還有傳說中的榮耀王者的段位,我這輩子是達不到了,也沒法教你們了,囧
  • 這個階段,我只推薦《程序員健康指南》一本書,保持身心健康,成為榮耀王者是早晚的事

下面開始我們的正文,倔強青銅篇目錄

  1. 環境搭建
  2. 第一個組件
  3. 組件嵌套和屬性傳遞
  4. 狀態處理
  5. 生命周期

環境搭建

默認大家已經有 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是入口文件,核心內容就是分別引入ReactReactDom,然後渲染了一個組件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組件了,自己實現組件也是分這麼幾個步驟

  1. import React
  2. 新建一個類,繼承React.ComponentReact里每個組件都可以寫成一個類
  3. 類的render函數返回值,就是顯示在頁面的內容
  4. render里返回的是東西有點詭異,表面上是html其實Babel會把JSX轉成React.createElememt來執行
  5. 由於JSX本質就是 js,class是 js 的關鍵字,所以要用className代替
  6. 如果想在JSX里渲染變數,使用{}包裹即可

現在[Babel官網]](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里也可以在{}內部使用三元表達式,大家可以修改isKingfalse試一試

然後就是渲染列表,我們使用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,我們稱之為構造函數,組件初始化狀態放在這裡,設置了isKingtrue,然後button元素上的onClick的時候,執行handleClick,在handleClick內部,調用this.setState來修改isKing

constructor函數里的bind是強行把handleClickthis綁定在組件上,否則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 更新完畢了

除了上面介紹的,還有需要注意的

  1. React16新增的componentDidCatch生命周期,用來處理報錯
  2. shouldComponentUpdate返回false,那麼組件就不會渲染
  3. 如果是子組件,還有個componentWillReceiveProps
  4. 組件卸載有componentWillUnmount,用來做資源的清理
  5. 合理利用生命周期,在不同的階段做不同的事情 如果你能看到這裡,那真的對React是真愛,恭喜你,你已經是秩序白銀啦,領取徽章

今天的代碼都在github

下期預告:秩序白銀篇-- 使用ant-designUI庫,有問題留言,我們還可以開黑,一起上王者


推薦閱讀:

如何評價React VR Project?
為什麼 GUI 編程中,Web 平台的技術革新特別火爆,而 Android 和 iOS 沒什麼成果?
知乎是否會停止使用React?
關於在react中request到底是應該寫在哪裡?
怎麼樣理解reactjs中組件的反模式?

TAG:React |