Thinking In React Way - 有限状态机

今天来聊聊前端,其实这个专题刚开始写起来的时候,是想和大家分享数据可视化的一些知识的。这也是图表君名头的由来,后来慢慢就写进了些前端的东西,再后来,因为图表君工作的转换,现在更多的做一些后台的工作,那么讨论的问题就更杂了,现在看起来算是我的一些工作和学习心得和感受吧。

好了,说了这么多。今天聊点什么呢?聊聊React。其实这也并不是什么新东西了。2014年,图表君就知道有这么个东西,听着几位业界大牛聊,说这东西有多么多么的好,当时也不是特别的理解,跟了一遍官方的Tutorial,也没有特别的感受。应该是因为当时前端的经验特别的浅(虽然现在也不敢说深,捂脸),没有什么特别的感受吧。

Angular的痛

后来做了几个项目,使用的是Angular,刚开始觉得双向数据绑定好牛逼啊,好好用,好好用。但是随着项目逐渐的一点点变大,感觉$scope上的东西是越来越多,各个controller里各有各的$scope,再加上$scope是继承的,当项目一复杂就越来越难以管理和控制。还有自己要封装一个组件在angular里得用directive吧,好吧看看directive的文档你就得晕了,link,compile,controller都是什么鬼。好了,今天不是吐槽angular的时间,但是angular得设计和使用的确是太复杂了。

前端到底是在干什么

好了,让我们先暂时跳出框架的讨论,来思考一下,前端的工作到底是干什么的?其实可以简单的说就是将数据到View的一个映射上,也就是说无论什么框架解决的基本问题就是讲数据展示到View上, 然后将讲用户的操作最后再反应到数据的变化上来。



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



再想清楚这个问题之后,React是怎么做的呢?React并不是一个完整的前端框架,只是一个专注于渲染View的library,在看了React的文档之后,我们会发现他的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的经验,看这样的代码也不会有什么特别的问题。好了,今天图表君不打算安利React,并不想写一个hello world出来。这样的文章太多,看看React的官方例子会比图表君写的好很多。那么今天说什么呢?

React Thinking - 状态机

看这部分之前,图表君强烈建议你可以看一看React的官方tutorialtutorial,很好的一个例子,也不长。一个小时就能看完,自己上手写一写,感受会更深。好了现在假设你看完了这个tutorial有什么感觉?

图表君的最大的感受是,最后将State,function都定义到了Game的这个Root级别的Component上了,再把所有的数据和function都传进自己的子Component里,需要的地方直接调用就好了。这样就使得我们上边说把Data的操作逻辑都被提出来,并集中在一起了,一下就清晰了,明确了。App管理从此变得一下简单了。反复品味这样的设计,忽然有个东西,进入了我的思维里。这东西不就是一个有限状态机呀。

有限状态机

fsm.png

有限状态机是个十分有用的模型,可以用来模拟世界上大部分的事物,其有三个特征:

  1. 状态总数(state)是有限的。
  2. 任一时刻,只处在一种状态之中。
  3. 某种条件下,会从一种状态转变(transition)到另一种状态。

我们再来看看例子中的代码

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>
    );
  }
}

构造方法,constructor - 定义了APP的初始状态。

handleClick - 定义了在棋盘里点击事件后的APP状态的变化。

jumpTo - 定义点击历史记录中某一步后APP的状态变化。

render- 描述如何在View上来展示当前的状态。

这样精巧的设计,facebook果然聚集了当今世界一流的工程师。然后我看了阮一峰的这篇介绍有限状态机的文章,看到这段代码。

var menu = {
      
    // 当前状态
    currentState: 'hide',
  
    // 绑定事件
    initialize: function() {
      var self = this;
      self.on("hover", self.transition);
    },
  
    // 状态转换
    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,到底干了一件什么事?帮我们做了这样的一个状态机啊,我们开发者只要定义Action,Reducer,他把我们的APP组织成了一个状态机。

从这样的角度再来看React,Redux这个的技术栈,我觉得理解的更加的清楚了,当然这仅仅是我的一点点小小的思考,欢迎大家一起讨论拍砖,后边逐步的和大家分享我的心得体会。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 阳光让乌云带上了帽子 安静潮湿 篮球场上只有三讲行人 滴答滴答 一人一赶车 卧床简书夜已深
    初鳕阅读 139评论 0 0
  • 毕业典礼那天,我会告诉自己不准哭。但99巴仙的几率我一定掉下眼泪,因为我看见我的同学哭了 这一年下来,感觉自己什么...
    对的时刻ww阅读 77评论 0 0
  • 第一件:定投! 我家楼下有一对卖农产品的夫妇,因为他们菜品新鲜为人很随和热情所以每次买菜很喜欢和他们聊...
    阳光小鹿530阅读 195评论 0 2
  • 在我们这个星球上,每天都要发生许多变化,有人倒霉了;有人走运了;有人在创造历史,历史也在成全或抛弃某些人。每一分钟...
    清语宛如阅读 1,569评论 1 2