本文共 9157 字,大约阅读时间需要 30 分钟。
react中的状态机
Mixing React and state machines is a great productivity boost for you as a developer. It also improves the usually shaky developers/designers collaboration.
混合使用React和状态机可以极大地提高您作为开发人员的工作效率。 它还可以改善通常不稳定的开发人员/设计人员之间的协作。
The state machine concept is very simple: a component can be in one state at a time and has a finite number of states.
状态机的概念非常简单:一个组件一次只能处于一种状态,并且具有有限数量的状态。
How is this helpful in UI development you say?
您说这对UI开发有什么帮助?
Let us consider a simple text edition component like the very poorly styled one below:
让我们考虑一个简单的文本编辑组件,例如以下样式很差的组件:
The possible “states” of the such a component are (from left to right):
此类组件的可能“状态”为(从左到右):
A straightforward shape for the component model has 5 properties:
组件模型的简单形状具有5个属性:
state: { processing: true, // Will be true when saving is in progress error: null, // Will be not null when a save error occurs value: null, // The read only display value edition: false, // Are we in edit mode? editValue: null, // The currently edited but not saved value}
The proper combinations of the properties will give us the 4 states we have identified above.
属性的正确组合将为我们提供上面确定的4种状态。
The problem is that there are actually 2⁵ = 32 possible combinations for the state. This means there are 28 wrong ways to use the state properties.
问题是该状态实际上有2⁵= 32种可能的组合。 这意味着有28种错误的方式使用状态属性。
One typical error on the component above is to not reset the error after a successful save. So the end user will save, get a “Something went wrong”
error message, correct the error, save again and go to display mode. So far so good. Except when going to edit mode again … the error message is still there. True story. I’ve seen this done several times by inexperienced developers.
上面的组件的一个典型错误是成功保存后不重置该错误。 因此,最终用户将进行保存,得到“Something went wrong”
出现“Something went wrong”
错误消息,更正错误,再次保存并进入显示模式。 到目前为止,一切都很好。 除了再次进入编辑模式时,错误消息仍然存在。 真实的故事。 我已经看到经验不足的开发人员多次这样做。
Our component is as simple as it gets and yet it evinces a sad truth:
我们的组件非常简单,但却显示出一个可悲的事实:
Operating on raw state properties means the component robustness relies solely on the correct use of the properties meaning … for each developer modifying the code … through the whole project lifecycle.
对原始状态属性进行操作意味着组件的健壮性完全取决于属性的正确使用,这意味着…对于每个修改代码的开发人员…在整个项目生命周期中。
We all know how this ends!
我们都知道结局!
Consider a different approach using “state machines”. The states would be:
考虑使用“状态机”的另一种方法。 状态将是:
state: { display: { processing: false, error: null, value: “Awesome”, edition: false, editValue: null, }, saving: { processing: true, error: null, value: “Awesome”, edition: true, // Keep the edit view active until save is finished editValue: “Awesome Edit”, }, edit: { processing: false, error: null, value: “Awesome”, edition: true, editValue: “Awesome Editing”, }, save_error: { processing: false, error: “Value should be at least 4 characters”, value: “Awesome”, edition: true, // Keep the edit box open editValue: “Awe”, }}
This is more verbose than the first approach but it provides many benefits:
这比第一种方法更为冗长,但是它提供了许多好处:
The convention on how to extend the component is clear: create a new state and set the raw properties appropriately. No one in their right mind would dare to use raw setState()
when there is a state machine implemented in the component.
关于如何扩展组件的约定很明确:创建一个新状态并适当设置原始属性。 当组件中实现了状态机时,没有一个人会敢于使用raw setState()
。
A minimalistic working version of the example above would be:
上面示例的简约工作版本为:
import React, {Component, PropTypes} from 'react';export default class InputStateMachine extends Component { constructor(props) { super(props); this.handleSubmit = this.handleSubmit.bind(this); this.goToState = this.goToState.bind(this); this.save = this.save.bind(this); this.state = { name: 'display', machine: this.generateState('display', props.initialValue) }; } generateState(stateName, stateParam) { const previousState = this.state ? {...this.state.machine} : {}; switch(stateName) { case 'display': return { processing: false, error: null, value: stateParam || previousState.value, editing: false, editValue: null, }; case 'saving': return { processing: true, error: null, // Reset any previous error value: previousState.value, editing: true, // Keep the edit view active until save is finished editValue: previousState.editValue, }; case 'edit': return { processing: false, error: null, value: previousState.value, editing: true, editValue: stateParam, }; case 'save_error': return { processing: false, error: stateParam, value: previousState.value, editing: true, // Keep the edit box open editValue: previousState.editValue, }; case 'loading': // Same as default default: return { processing: true, error: null, value: null, editing: false, editValue: null, }; } } goToState(stateName, stateParam) { this.setState({ name: stateName, machine: this.generateState(stateName, stateParam) }); } handleSubmit(e) { this.goToState('edit', e.target.value); }; save(valueToSave) { this.goToState('saving'); // Simulate saving the data ... setTimeout(() => this.goToState('display', valueToSave), 2000); }; render() { const {processing, error, value, editing, editValue} = this.state.machine; if(processing) { returnProcessing ...
} else if(editing) { return ({error &&); } else { return (Error: {error}
}); } }}{value}
Usage is:
用法是:
There is a bit of boilerplate code to write when using state machines:
使用状态机时,需要编写一些样板代码:
Destructure this.state.machine
instead of this.state
in your render method
this.state.machine
而不是this.state
this.state
在您的渲染方法中
Some libraries aim to solve this boilerplate issue but the overhead is so small that it does not really deserve a new dependency on your project.
一些库旨在解决此样板问题,但是开销如此之小,以至于它实际上不值得您的项目依赖。
The state machine pattern is a good way to improve your UI components readability and development process from visual design to maintenance.
从视觉设计到维护,状态机模式是提高UI组件的可读性和开发过程的好方法。
Careful though! Do not go all in and apply this to all the components you have! Your app needs to remain flexible and handle emergent complexities. The number of states can quickly explode for higher level components and state machines are of no benefit in that case.
小心点! 不要全力以赴,并将其应用于您拥有的所有组件! 您的应用程序需要保持灵活性并应对紧急情况。 对于更高级别的组件,状态数量会Swift爆炸,而在这种情况下,状态机毫无用处。
Do use the pattern on your library of standard/base components though! This is the part of the application that will live the longest. Eventually, each developer in the team will touch it and benefit from the guidance and robustness provided by the state machine.
不过,请务必在您的标准/基本组件库中使用该模式! 这是应用程序中寿命最长的部分。 最终,团队中的每个开发人员都会接触它,并从状态机提供的指导和强大功能中受益。
Thanks for reading!
谢谢阅读!
翻译自:
react中的状态机
转载地址:http://tjwzd.baihongyu.com/