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

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

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

  1. 倔強青銅
    • 初入峽谷的初始段位,默認召喚師已經有了ES6nodejs 的基礎
    • 使用 create-react-app 創建 React 開發環境
    • 學習 React 世界裏的基本玩法,例如組件化,JSX,事件監聽,內部 state,組件的props、生命週期函數等
    • 這篇文章主要介紹 React 青銅升白銀鬚要的基礎知識,看完你就白銀啦
  2. 秩序白銀
    • 到了白銀段位,基本都是有了基本的操做,不會出現呆萌的站在地方塔下被打死的狀況了
    • 咱們須要買一個皮膚來提高頁面美觀而且多加練習
    • 學習使用螞蟻金服 ant-design 的使用
  3. 榮耀黃金前端

    • 到了這個階段,召喚師對 React 有了基本的認識,想進一步的提高段位,咱們須要提升本身的大局觀
    • 學習使用 React-Router4 來讓咱們有多面做戰能力
    • 學會使用 BrowserRouterRouterLink 等組件
    • 學會使用 Redux 和隊友配合,修煉大局觀
    • 瞭解單項數據流開發模式和 Redux 的各類概念,如 dispatch,action,reducers
    • 使用 react-redux 更好的和 Redux 配合有大局觀意識,上鉑金也是很 easy 了
  4. 尊貴鉑金node

    • 不少召喚師卡在鉑金上不去,由於鉑金想上鑽石,須要瞭解更多的細節和原理
    • React 原理剖析
    • 對本身技能的原理有深入的瞭解,上鑽石必備
  5. 永恆鑽石react

    • 鑽石段位開始了徵兆模式,召喚師的技能池要足夠深才能更進一步,對本身擅長技能的理解也要更深入
    • Redux 中間件機制,實現本身的中間件
    • 常見的React 性能優化方式
    • 服務端渲染
    • Redux 以外其餘的數據解決方案如 mobxdva
  6. 至尊星耀程序員

    • 這個段位已是獨當一面的強者了,目標僅限於 React 這個庫很難更近一層,須要瞭解更底層的原理
    • Redux 原理剖析+實現本身的 Redux
    • React-Router+實現本身的 React-Router
    • Webppack 工做機制和原理剖析
    • Babel 工做機制和原理剖析
  7. 最強王者
    • 達到最強王者已是頂尖召喚師,在整個 React 峽谷都是鼎鼎大名的存在,據說上面還有傳說中的榮耀王者的段位,我這輩子是達不到了,也無法教大家了,囧
    • 這個階段,我只推薦《程序員健康指南》一本書,保持身心健康,成爲榮耀王者是遲早的事

開始以前,作個小廣告,歡迎你們關注我在慕課網的React實戰課程Redux+React Router+Node.js全棧開發npm

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

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

環境搭建

默認你們已經有 node 環境了,先安裝腳手架數組

npm install create-react-app -g複製代碼

而後創建項目,並啓動性能優化

create-react-app bronze
cd bronze
npm 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官網],看下 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 組件是否應該渲染, 默認返回 true
componentWillUpdate,組件 App 準備更新了
組件 App 正在渲染
componentDidUpdate, 組件 App 更新完畢了複製代碼

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

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

歡迎你們關注我在慕課網的實戰課程Redux+React Router+Node.js全棧開發

下期預告:秩序白銀篇-- 使用 ant-design UI庫,有問題留言,咱們還能夠開黑,一塊兒上王者

相關文章
相關標籤/搜索