Skip to content

Commit 0333b67

Browse files
docs(website): update statechart docs
1 parent 40bb0af commit 0333b67

File tree

4 files changed

+66
-52
lines changed

4 files changed

+66
-52
lines changed

packages/overmind-website/examples/guide/statecharts/condition.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default (ts, view) =>
44
{
55
fileName: 'overmind/login/index.ts',
66
code: `
7-
import { Statechart, statecharts } from 'overmind/config'
7+
import { Statechart, statechart } from 'overmind/config'
88
import * as actions from './actions'
99
import { state } from './state'
1010
@@ -35,15 +35,15 @@ const loginChart: Statechart<typeof config, {
3535
}
3636
}
3737
38-
export default statecharts(config, loginChart)
38+
export default statechart(config, loginChart)
3939
`,
4040
},
4141
]
4242
: [
4343
{
4444
fileName: 'overmind/login/index.ts',
4545
code: `
46-
import { statecharts } from 'overmind/config'
46+
import { statechart } from 'overmind/config'
4747
import * as actions from './actions'
4848
import { state } from './state'
4949
@@ -69,7 +69,7 @@ const loginChart = {
6969
}
7070
}
7171
72-
export default statecharts(config, loginChart)
72+
export default statechart(config, loginChart)
7373
`,
7474
},
7575
]

packages/overmind-website/examples/guide/statecharts/define.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default (ts, view) =>
44
{
55
fileName: 'overmind/login/index.ts',
66
code: `
7-
import { Statechart, statecharts } from 'overmind/config'
7+
import { Statechart, statechart } from 'overmind/config'
88
import * as actions from './actions'
99
import { state } from './state'
1010
@@ -47,15 +47,15 @@ const loginChart: Statechart<typeof config, {
4747
}
4848
}
4949
50-
export default statecharts(config, loginChart)
50+
export default statechart(config, loginChart)
5151
`,
5252
},
5353
]
5454
: [
5555
{
5656
fileName: 'overmind/login/index.js',
5757
code: `
58-
import { statecharts } from 'overmind/config'
58+
import { statechart } from 'overmind/config'
5959
import * as actions from './actions'
6060
import { state } from './state'
6161
@@ -93,7 +93,7 @@ const loginChart = {
9393
}
9494
}
9595
96-
export default statecharts(config, loginChart)
96+
export default statechart(config, loginChart)
9797
`,
9898
},
9999
]

packages/overmind-website/examples/guide/statecharts/nested.ts

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default (ts, view) =>
44
{
55
fileName: 'overmind/dashboard/index.ts',
66
code: `
7-
import { Statechart, statecharts } from 'overmind/config'
7+
import { Statechart, statechart } from 'overmind/config'
88
import * as actions from './actions'
99
import { state } from './state'
1010
@@ -70,39 +70,35 @@ const projectsChart: Statechart<typeof config, {
7070
}
7171
7272
const dashboardChart: Statechart<typeof config, {
73-
ISSUES: {
74-
issues: typeof issuesChart
75-
}
76-
PROJECTS: {
77-
projects: typeof projectsChart
78-
}
73+
ISSUES: typeof issuesChart
74+
PROJECTS: typeof projectsChart
7975
}> = {
8076
initial: 'ISSUES',
8177
states: {
8278
ISSUES: {
8379
on: {
8480
openProjects: 'PROJECTS'
8581
},
86-
charts: { issuesChart }
82+
chart: issuesChart
8783
},
8884
PROJECTS: {
8985
on: {
9086
openIssues: 'ISSUES'
9187
},
92-
charts: { projectsChart }
88+
chart: projectsChart
9389
}
9490
}
9591
}
9692
97-
export default statecharts(config, dashboardChart)
93+
export default statechart(config, dashboardChart)
9894
`,
9995
},
10096
]
10197
: [
10298
{
10399
fileName: 'overmind/dashboard/index.ts',
104100
code: `
105-
import { statecharts } from 'overmind/config'
101+
import { statechart } from 'overmind/config'
106102
import * as actions from './actions'
107103
import { state } from './state'
108104
@@ -167,18 +163,18 @@ const dashboardChart = {
167163
on: {
168164
openProjects: 'PROJECTS'
169165
},
170-
charts: { issuesChart }
166+
chart: issuesChart
171167
},
172168
PROJECTS: {
173169
on: {
174170
openIssues: 'ISSUES'
175171
},
176-
charts: { projectsChart }
172+
chart: projectsChart
177173
}
178174
}
179175
}
180176
181-
export default statecharts(config, dashboardChart)
177+
export default statechart(config, dashboardChart)
182178
`,
183179
},
184180
]

packages/overmind-website/guides/intermediate/06_statecharts.md

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Just like [operators](/guides/intermediate/04_goingfunctional) is a declarative abstraction over plain actions, **statecharts** is a declarative abtraction over an Overmind configuration of **state** and **actions**. That means you will define your charts by:
44

55
```js
6-
const configWithStatechart = statecharts(config, charts)
6+
const configWithStatechart = statechart(config, chart)
77
```
88

99
There are several benefits to using statecharts:
@@ -14,9 +14,11 @@ There are several benefits to using statecharts:
1414
4. Your state definition is cleaned up as your **isLoading** types of state is no longer needed
1515
5. You have a tool to do "top down" implementation instead of "bottom up"
1616

17-
You can basically think of a statechart as a way of limiting what actions are available to be executed in certain transition states. This concept is very old and was originally used to design machines where the user was exposed to all points of interaction, all buttons and switches, at any time. Statecharts would help make sure that at certain transition states certain buttons and switches would not operate.
17+
You can basically think of a statechart as a way of limiting what actions are available to be executed in certain states of the application. This concept is very old and was originally used to design machines where the user was exposed to all points of interaction, all buttons and switches, at any time. Statecharts would help make sure that at certain states certain buttons and switches would not operate.
1818

19-
A simple example of this is a Walkman. When the Walkman is in a **playing** transition state you should not be able to hit the **eject** button. On the web this might seem unnecessary as points of interaction is dynamic. We simply hide and/or disable buttons. But this is the exact problem. It is fragile. It is fragile because the UI implementation itself is all you depend on to prevent logic from running when it should not. A statechart is a much more resiliant way to ensure what logic can actually run in any given state.
19+
A simple example of this is a Walkman. When the Walkman is in a **playing** state you should not be able to hit the **eject** button. On the web this might seem unnecessary as points of interaction is dynamic. We simply hide and/or disable buttons. But this is the exact problem. It is fragile. It is fragile because the UI implementation itself is all you depend on to prevent logic from running when it should not. A statechart is a much more resiliant way to ensure what logic can actually run in any given state.
20+
21+
In Overmind we talk about these statechart states as **transition states**.
2022

2123
## Defining a statechart
2224

@@ -61,6 +63,43 @@ This approach has three benefits:
6163
2. When typing your application the actions already has a typed input, which would not be possible with a generic **transition** action
6264
3. It is simpler concept both in code and for your brain
6365

66+
What to take notice of is that the **action** causing the transition is run before the transition actually happens. That means the action runs in the context of the current transition state and any synchronous calls to another action will obey its rules. If the action does something asynchronous, like doing an HTTP request, the transition will be performed and the asynchronous logic will run in the context of the new transition state.
67+
68+
```js
69+
const myTransitionAction = async ({ actions }) => {
70+
// I am still in the current transition state
71+
actions.someOtherAction()
72+
73+
await Promise.resolve()
74+
75+
// I am in the new transition state
76+
actions.someOtherAction()
77+
}
78+
```
79+
80+
## Nested statecharts
81+
82+
With a more complicated UI we can create nested statecharts. An example of this would be a workspace UI with different tabs. You only want to allow certain actions when the related tab is active. Let us explore an example:
83+
84+
```marksy
85+
h(Example, { name: "guide/statecharts/nested.ts" })
86+
```
87+
88+
What to take notice of in this example is that all chart states has its own **chart** property, which allows them to be nested. The nested charts has access to the same actions and state as the parent chart.
89+
90+
In this example we also took advantage of the **entry** and **exit** hooks of a transition state. These also points to actions. When a transition is made into the transition state, the **entry** will run. This behavior is nested. When an **exit** hook exists and a transition is made away from the transition state, it will also run. This behavior is also nested of course.
91+
92+
## Parallel statecharts
93+
94+
It is also possible to define your charts in a parallel manner. You do this by simply using an object of keys where the key represents an ID of the chart. The **chart** property on a transition state allows the same. Either a single chart or an object of multiple charts where the key represents an ID of the chart.
95+
96+
```js
97+
export default statechart(config, {
98+
issues: issuesChart,
99+
projects: projectsChart
100+
})
101+
```
102+
64103
## Conditions
65104

66105
In our chart above we let the user log in even though there is no **username** or **password**. That seems a bit silly. In statecharts you can define conditions. These conditions receives the state of the configuration and returns true or false.
@@ -86,7 +125,7 @@ As you can see we have no state indicating that we have received an error, like
86125
password: '',
87126
user: null,
88127
authenticationError: null,
89-
states: [['ROOT_CHART', 'LOGIN']],
128+
states: [['CHART', 'LOGIN']],
90129
actions: {
91130
changeUsername: true,
92131
changePassword: true,
@@ -97,11 +136,13 @@ As you can see we have no state indicating that we have received an error, like
97136
}
98137
```
99138

100-
The **states** state is the current transition states. It is defined as an array of arrays. This indicates that we can have parallel and nested charts.
139+
The **states** state is the current transition states. It is defined as an array of arrays. This indicates that we can have parallel and nested charts. The **CHART** symbol in the array indicates that you have defined an immediate chart. If you rather defined parallel charts you would define your own ids.
101140

102141
The **actions** state is a derived state. That means it automatically updates based on the current state of the chart. This is helpful for your UI implementation. It can use it to disable buttons etc. to help the user understand when certain actions are possible.
103142

104-
There is also a third derived state called **matches**. This derived state returns a function that allows you to figure out what state you are in:
143+
## Identifying states
144+
145+
There is also a third derived state called **matches**. This derived state returns a function that allows you to figure out what state you are in. This is also the API you use in your components to identify the state of your application:
105146

106147
```marksy
107148
h(Example, { name: "guide/statecharts/matches.ts" })
@@ -123,31 +164,8 @@ h(Example, { name: "guide/statecharts/actions.ts" })
123164

124165
What to take notice of here is that with traditional Overmind we would most likely just set the **user** or the **authenticationError** directly in the **login** action. That is not the case with statcharts because our actions are the triggers for transitions. That means whenever we want to deal with transitions we create an action for it, even completely empty actions like **tryAgain**. This simplifies our chart definition and also we avoid having a generic **transition** action that would not be typed in TypeScript etc.
125166

126-
## Nested statecharts
127-
128-
With a more complicated UI we can create nested statecharts. An example of this would be a workspace UI with different tabs. You only want to allow certain actions when the related tab is active. Let us explore an example:
129-
130-
```marksy
131-
h(Example, { name: "guide/statecharts/nested.ts" })
132-
```
133-
134-
What to take notice of in this example is that all chart states has its own **charts** property, which allows them to be nested. The nested charts has access to the same actions and state as the parent chart.
135-
136-
In this example we also took advantage of the **entry** and **exit** hooks of a transition state. These also points to actions. When a transition is made into the transition state, the **entry** will run. This behavior is nested. When an exit hook exists and a transition is made away from the transition state, it will also run. This behavior is also nested of course.
137-
138-
## Parallel statecharts
139-
140-
It is also possible to define your charts in a parallel manner. The above example of projects and issues could have been defined as:
141-
142-
```js
143-
export default statecharts(config, {
144-
issues: issuesChart,
145-
projects: projectsChart
146-
})
147-
```
148-
149-
Now these two charts would operate individually. This is also the case for the **charts** property on the states of a chart.
150167

168+
Now these two charts would operate individually. This is also the case for the **chart** property on the states of a chart.
151169

152170
## Devtools
153171

0 commit comments

Comments
 (0)