Thinking In React Way - 有限狀態(tài)機

今天來聊聊前端,其實這個專題剛開始寫起來的時候,是想和大家分享數(shù)據(jù)可視化的一些知識的。這也是圖表君名頭的由來,后來慢慢就寫進(jìn)了些前端的東西,再后來,因為圖表君工作的轉(zhuǎn)換,現(xiàn)在更多的做一些后臺的工作,那么討論的問題就更雜了,現(xiàn)在看起來算是我的一些工作和學(xué)習(xí)心得和感受吧。

好了,說了這么多。今天聊點什么呢?聊聊React。其實這也并不是什么新東西了。2014年,圖表君就知道有這么個東西,聽著幾位業(yè)界大牛聊,說這東西有多么多么的好,當(dāng)時也不是特別的理解,跟了一遍官方的Tutorial,也沒有特別的感受。應(yīng)該是因為當(dāng)時前端的經(jīng)驗特別的淺(雖然現(xiàn)在也不敢說深,捂臉),沒有什么特別的感受吧。

Angular的痛

后來做了幾個項目,使用的是Angular,剛開始覺得雙向數(shù)據(jù)綁定好牛逼啊,好好用,好好用。但是隨著項目逐漸的一點點變大,感覺$scope上的東西是越來越多,各個controller里各有各的$scope,再加上$scope是繼承的,當(dāng)項目一復(fù)雜就越來越難以管理和控制。還有自己要封裝一個組件在angular里得用directive吧,好吧看看directive的文檔你就得暈了,link,compile,controller都是什么鬼。好了,今天不是吐槽angular的時間,但是angular得設(shè)計和使用的確是太復(fù)雜了。

前端到底是在干什么

好了,讓我們先暫時跳出框架的討論,來思考一下,前端的工作到底是干什么的?其實可以簡單的說就是將數(shù)據(jù)到View的一個映射上,也就是說無論什么框架解決的基本問題就是講數(shù)據(jù)展示到View上, 然后將講用戶的操作最后再反應(yīng)到數(shù)據(jù)的變化上來。



                    Data --> Whatever FrameWork --> View
                    Data <-- Whatever FrameWork <-- View



再想清楚這個問題之后,React是怎么做的呢?React并不是一個完整的前端框架,只是一個專注于渲染View的library,在看了React的文檔之后,我們會發(fā)現(xiàn)他的api是很簡單的。一個典型的react的組件

class ShoppingList extends React.Component {
  render() {
    return (
      <div className="shopping-list">
        <h1>Shopping List for {this.props.name}</h1>
        <ul>
          <li>Instagram</li>
          <li>WhatsApp</li>
          <li>Oculus</li>
        </ul>
      </div>
    );
  }
}

// Example usage: <ShoppingList name="Mark" />

即使你沒有React的經(jīng)驗,看這樣的代碼也不會有什么特別的問題。好了,今天圖表君不打算安利React,并不想寫一個hello world出來。這樣的文章太多,看看React的官方例子會比圖表君寫的好很多。那么今天說什么呢?

React Thinking - 狀態(tài)機

看這部分之前,圖表君強烈建議你可以看一看React的官方tutorialtutorial,很好的一個例子,也不長。一個小時就能看完,自己上手寫一寫,感受會更深。好了現(xiàn)在假設(shè)你看完了這個tutorial有什么感覺?

圖表君的最大的感受是,最后將State,function都定義到了Game的這個Root級別的Component上了,再把所有的數(shù)據(jù)和function都傳進(jìn)自己的子Component里,需要的地方直接調(diào)用就好了。這樣就使得我們上邊說把Data的操作邏輯都被提出來,并集中在一起了,一下就清晰了,明確了。App管理從此變得一下簡單了。反復(fù)品味這樣的設(shè)計,忽然有個東西,進(jìn)入了我的思維里。這東西不就是一個有限狀態(tài)機呀。

有限狀態(tài)機

fsm.png

有限狀態(tài)機是個十分有用的模型,可以用來模擬世界上大部分的事物,其有三個特征:

  1. 狀態(tài)總數(shù)(state)是有限的。
  2. 任一時刻,只處在一種狀態(tài)之中。
  3. 某種條件下,會從一種狀態(tài)轉(zhuǎn)變(transition)到另一種狀態(tài)。

我們再來看看例子中的代碼

class Game extends React.Component {
  constructor(){
    super();
    this.state={
      history:[{
        squares: Array(9).fill(null)
      }],
      stepNumber: 0,
      xIsNext: true
    }
  }
  
  handleClick(i){
    const history = this.state.history;
    const stepNumber = this.state.stepNumber
    const current = history[history.length - 1];
    const squares = current.squares.slice();
    if (calculateWinner(squares) || squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext? 'X':'O';
    this.setState(
      {
        history: history.concat([{
      squares: squares   
    }]),
        stepNumber: stepNumber + 1,
    xIsNext: !this.state.xIsNext,
      }
    )
  }
  
  jumpTo(step){
    const newHistory = this.state.history.slice(0,step+1)
    console.log(newHistory);
    this.setState({
      history: newHistory,
      stepNumber:step,
      xIsNext: (step % 2) ? false: true, 
    })
  }
  
  render() {
    const history = this.state.history;
    const current = history[this.state.stepNumber];
    const winner = calculateWinner(current.squares);
    let status;
    if(winner){
       status = 'Winner Is :' + winner;
    }else{
       status = 'Next player: ' + (this.state.xIsNext ? 'X':'O');
    }
    const moves = history.map((step,move) => {
       const desc = move ? 'Move #' + move : 'Game Start';
       return(
         <li key={move}>
            <a href="#" onClick={() => this.jumpTo(move)}>{desc}</a>
         </li> 
       )
    });
    return (
      <div className="game">
        <div className="game-board">
          <Board squares={current.squares} onClick={(i) => this.handleClick(i)} />
        </div>
        <div className="game-info">
          <div>{status}</div>
          <ol>{moves}</ol>
        </div>
      </div>
    );
  }
}

構(gòu)造方法,constructor - 定義了APP的初始狀態(tài)。

handleClick - 定義了在棋盤里點擊事件后的APP狀態(tài)的變化。

jumpTo - 定義點擊歷史記錄中某一步后APP的狀態(tài)變化。

render- 描述如何在View上來展示當(dāng)前的狀態(tài)。

這樣精巧的設(shè)計,facebook果然聚集了當(dāng)今世界一流的工程師。然后我看了阮一峰的這篇介紹有限狀態(tài)機的文章,看到這段代碼。

var menu = {
      
    // 當(dāng)前狀態(tài)
    currentState: 'hide',
  
    // 綁定事件
    initialize: function() {
      var self = this;
      self.on("hover", self.transition);
    },
  
    // 狀態(tài)轉(zhuǎn)換
    transition: function(event){
      switch(this.currentState) {
        case "hide":
          this.currentState = 'show';
          doSomething();
          break;
        case "show":
          this.currentState = 'hide';
          doSomething();
          break;
        default:
          console.log('Invalid State!');
          break;
      }
    }
  
  };
  

有沒有似曾相識的感覺,Redux里是不是就是這么干的?然后再想想Redux,到底干了一件什么事?幫我們做了這樣的一個狀態(tài)機啊,我們開發(fā)者只要定義Action,Reducer,他把我們的APP組織成了一個狀態(tài)機。

從這樣的角度再來看React,Redux這個的技術(shù)棧,我覺得理解的更加的清楚了,當(dāng)然這僅僅是我的一點點小小的思考,歡迎大家一起討論拍磚,后邊逐步的和大家分享我的心得體會。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,030評論 25 709
  • 陽光讓烏云帶上了帽子 安靜潮濕 籃球場上只有三講行人 滴答滴答 一人一趕車 臥床簡書夜已深
    初鱈閱讀 251評論 0 0
  • 畢業(yè)典禮那天,我會告訴自己不準(zhǔn)哭。但99巴仙的幾率我一定掉下眼淚,因為我看見我的同學(xué)哭了 這一年下來,感覺自己什么...
    對的時刻ww閱讀 168評論 0 0
  • 第一件:定投! 我家樓下有一對賣農(nóng)產(chǎn)品的夫婦,因為他們菜品新鮮為人很隨和熱情所以每次買菜很喜歡和他們聊...
    陽光小鹿530閱讀 285評論 0 2
  • 在我們這個星球上,每天都要發(fā)生許多變化,有人倒霉了;有人走運了;有人在創(chuàng)造歷史,歷史也在成全或拋棄某些人。每一分鐘...
    清語宛如閱讀 1,683評論 1 2

友情鏈接更多精彩內(nèi)容