##有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
React和React Native的状态
##有限状态机(Finite-state machine)是一个非常有用的模型,可以模拟世界上大部分事物。
简单说,它有三个典型特征:
1:事物包含的状态总数(state)是有限的。
2:任一时刻,事物仅且只能处于一种状态之中。
3:某种事件驱动下,可以导致事物从一种状态切换到另一种状态。
在维基百科中称:有限状态机FSM是设计和实现事件驱动程序内复杂行为组织原则的有力工具。
传统的MVC设计中
它对JavaScript的意义在于,很多对象可以写成有限状态机。
有限状态机的写法,逻辑清晰,表达力强,有利于封装事件。一个对象的状态越多、发生的事件越多,就越适合采用有限状态机的写法。
另外,JavaScript语言是一种异步操作特别多的语言,常用的解决方法是指定回调函数,但这样会造成代码结构混乱、难以测试和除错等问题。有限状态机提供了更好的办法:把异步操作与对象的状态改变挂钩,当异步操作结束的时候,发生相应的状态改变,由此再触发其他操作。这要比回调函数、事件监听、发布/订阅等解决方案,在逻辑上更合理,更易于降低代码的复杂度。
有限状态机非常重要的一点就是讲用户的操作行为,也就是组件的事件响应与组件的表现分离开来.通过建立一个有限状态机的组件时,我们完全不关心用户的操作行为具体做了什么,这时组件可能会有几种状态对应不同的表现形式,而用户触发的事件仅仅是切换了模型的状态.至于每个状态的具体表现和行为,我们完全可以单独定义,也就说这时一种行为和响应上的解耦.
当用户的操作发生变化的时候,我们仅仅需要改变根数据,也就是state源.而不需要像以往的MVC设计中,当行为发生时,我们既需要在C层改变Model,同时还要操作View进行更新.在复杂的交互场景中代码尤其臃肿难以维护.状态机的设计思路,很好的解决了这个问题,用户操作行为仅仅与修改数据关联,而与其他无关.
React框架中将UI简单的看作有点状态机的组件集合。将UI看作包含了各种各样的状态的组件,并在各种状态间切换,很容易保持UI的一致性。在React中,你只要改变组件的状态,就会自动重新渲染UI,React会在最有高效的方式下更新虚拟DOM。
通过调用setState(data, callback)方法,改变状态,就会触发React更新UI。大部分情况下,我们不需要提供callback函数。React会自动的帮我们更新UI。
后面在好好看看这个callback的功能和调用时机。
使用React组件时,免不了就需要跟props,state这两个属性打交道.
props是从父组件或者组件创建时外部传递来的,大多数组件在创建时就可以使用各种参数来进行定制,这些定制的参数就props,props是在父组件中指定,而且一经指定,在被指定的组件的生命周期中则不再改变
state也是用来控制描述一个组件的,对于需要改变的数据,我们需要使用state。
那么什么样的组件该有state呢?
大部分的组件应该从props属性中获取数据并渲染。但有的时候组件得相应用户输入或者交互响应,或同服务器交互,这些情况下会用到state。React的官方说法是:尽可能的保持你的组件无状态化(个人的理解就是更好的贴合单向数据流这一理念)。为了实现这个目标,得保持你的状态同业务逻辑分离,并减少冗余信息,尽可能保持组件的单一职责。
state应该包含什么样的数据
UI交互,服务器交互,会导致改变的数据。
state不应包含什么样的数据
1.计算过的数据
2.组件
3.从props复制的数据
React官方推荐的一种模式就是:构建几个无状态的组件用来渲染数据,在这些之上构建一个有状态的组件同用户和服务交互,数据通过props传递给无状态的组件。
React的作者认为,组件应该同关注分离,而不是同模板和展现逻辑分离。结构化标记和生成结构化标记的代码是紧密关联的,此外,展现逻辑一般都很复杂,使用模板语言会使展现变得笨重。
React解决这个问题的方式就是:直接通过JavaScript代码生成虚拟Dom和组件树,这样的话,你就可以使用JavaScript富丰的表达力去构建UI。为了使这个过程变得更简单,React创建了类似HTML的语法去构建节点树,也就是JSX了。这样可以更方便的创建模板化的组件,方便代码复用.
如果一个组件的数据都是不变的,这意味着UI显示部分也是不变的,那么它就不应当成为一个单独的RN组件,因为单独的RN组件肯定是数据会被改变的.
对于无状态的RN组件来说,会被改变的数据来自于它的props(属性),而对于有状态的RN组件来说,会被改变的数据不仅来自于它的props,还来自于它的state(状态机变量).尽可能的让自定义的组件成为无状态的RN组件,以为者尽可能的让自定义的RN组件没有状态机变量.
一个好的设计思路是:
创建多个只负责渲染的无状态的RN组件,将他们封装在一个有状态的RN组件中,并把这个有状态的RN组件的状态机变量的值通过props的形式传递给无状态的RN组件中.在这种设计思路下,有状态的RN组件封装了UI的交互逻辑,而无状态的RN组件只负责渲染UI界面.
但是状态机变量的改变会导致RN组件的重新渲染,所以提高RN应用程序性能的一种方式就是努力减少状态机变量的数目.
在RN组件的render函数中,在正确的位置引用状态机变量.
组件之间的通信:
父组件向子组件传递消息,数据通过回调父组件传递给自己的回调函数来实现.回调函数于父组件设定,被保存在子组件的某个属性中,等待需要向父组件传递消息的时候调用.
除了setState函数意外,RN还提供了replaceState函数与forceUpdate函数
状态机的优点:
1)有限状态机是定义组件的一种好用的设计模式,能够让组件的代码看起来更加清晰,而且易于理解;
2)有限状态机这种模式适合有明显状态特点的组件;
3)本文所举的例子不够贴近实际项目,近期会看看自己做过的项目中有哪些适合用状态机模式来重写的模块,到时候再写博客来与大家分享。
有一个异步操作(light.fadeOut)。如果不希望状态立即改变,就要让回调函数返回StateMachine.ASYNC,表示状态暂时不改变;等到异步操作结束,再调用transition方法,使得状态发生改变。