Skip to content

Commit 26b09ef

Browse files
christianalfonigitbook-bot
authored andcommitted
GitBook: [master] 10 pages modified
1 parent bb7b3ad commit 26b09ef

File tree

8 files changed

+155
-254
lines changed

8 files changed

+155
-254
lines changed

SUMMARY.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
## Core
1010

1111
* [State](core/defining-state.md)
12-
* [Actions](features/writing-application-logic.md)
13-
* [Effects](features/running-side-effects.md)
12+
* [Actions](core/writing-application-logic.md)
13+
* [Effects](core/running-side-effects.md)
1414
* [Operators](core/going-functional.md)
1515
* [Statecharts](features/statecharts.md)
1616
* [Typescript](core/typescript.md)

core/defining-state.md

Lines changed: 47 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,6 @@ You might wonder why **undefined** is not part of the core value types. Well, th
1919
1. It is not a serializable value. That means if you explicitly set a value to _undefined_ it will not show up in the devtools
2020
2. Undefined values can not be tracked. That means if you were to iterate an object and look at the keys of that object, any undefined values will not be tracked. This can cause unexpected behaviour
2121

22-
{% hint style="info" %}
23-
When writing Typescript you should **not** use optional values for your state \(**?**\), or use **undefined** in a union type. In a serializable state store world **null** is the value indicating _“there is no value”_.
24-
25-
```typescript
26-
type State = {
27-
// Do not do this
28-
foo?: string
29-
30-
// Do not do this
31-
foo: string | undefined
32-
33-
// Do this
34-
foo: string | null
35-
36-
// Or this, if there always will be a value there
37-
foo: string
38-
}
39-
40-
export const state: State = {
41-
foo: null
42-
}
43-
```
44-
{% endhint %}
45-
4622
### Naming
4723

4824
Each value needs to sit behind a name. Naming can be difficult, but we have some help. Even though we eventually do want to consume our application through a user interface we ideally want to avoid naming things specifically related to the environment where we show the user interface. Things like **page**, **tabs**, **modal** etc. are specific to a browser experience, maybe related to a certain size. We want to avoid those names as they should not dictate which elements are to be used with the state, that is up to the user interface to decide later. So here are some generic terms to use instead:
@@ -55,7 +31,7 @@ Each value needs to sit behind a name. Naming can be difficult, but we have some
5531

5632
The root value of your state tree is an object, because objects are great for holding other values. An object has keys that point to values. Most of these keys point to values that are the actual state of the application, but these keys can also represent domains of the application. A typical state structure could be:
5733

58-
```typescript
34+
```javascript
5935
{
6036
modes: ['issues', 'admin'],
6137
currentModeIndex: 0,
@@ -84,7 +60,7 @@ Arrays are similar to objects in the sense that they hold other values, but inst
8460

8561
Strings are of course used to represent text values. Names, descriptions and whatnot. But strings are also used for ids, types, etc. Strings can be used as values to reference other values. This is an important part in structuring state. For example in our **objects** example above we chose to use an array to represent the modes, using an index to point to the current mode, but we could also do:
8662

87-
```typescript
63+
```javascript
8864
{
8965
modes: {
9066
issues: 0,
@@ -115,53 +91,38 @@ All values, with the exception of booleans, can also be **null**. Non-existing.
11591

11692
A concept in Javascript called a [GETTER](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) allows you to intercept accessing a property in an object. A getter is just like a plain value, it can be added or removed at any point. Getters do **not** cache the result for that very reason, but whatever state they access is tracked.
11793

118-
{% code title="overmind/state.ts" %}
119-
```typescript
120-
export type User = {
121-
id: number
122-
firstName: string
123-
lastName: string
124-
readonly fullName: string
125-
}
126-
127-
export type State = {
128-
user: User
129-
}
130-
131-
export const state: State = {
94+
{% tabs %}
95+
{% tab title="overmind/state.js" %}
96+
```javascript
97+
export const state = {
13298
user: {
13399
id: 1,
134100
firstName: 'Bob',
135101
lastName: 'Jackson',
136-
get fullName(this: User) {
137-
return this.firstName + ' ' + this.lastName
138-
}
102+
jwt: '1234567'
103+
},
104+
get isLoggedIn() {
105+
return Boolean(this.user && this.user.jwt)
139106
}
140107
}
141108
```
142-
{% endcode %}
109+
{% endtab %}
110+
{% endtabs %}
143111

144112
### Cached getter
145113

146114
When you need to do more heavy calculation or combine state from different parts of the tree you can use a plain function instead. Overmind treats these functions like a **getter**, but the returned value is cached and they can also access the root state of the application. A simple example of this would be:
147115

116+
{% tabs %}
117+
{% tab title="overmind/state.js" %}
148118
```typescript
149-
import { Derive } from 'overmind'
150-
151-
export type State = {
152-
title: string
153-
upperTitle: Derive<State, string>
154-
}
155-
156119
export const state: State = {
157120
title: 'My awesome title',
158121
upperTitle: state => state.title.toUpperCase()
159122
}
160123
```
161-
162-
{% hint style="info" %}
163-
Is is important that you define your state with a **type**, do **NOT** use an **interface**
164-
{% endhint %}
124+
{% endtab %}
125+
{% endtabs %}
165126

166127
The first argument of the function is the state the derived function is attached to. A second argument is also passed and that is the root state of the application, allowing you to access whatever you would need. Two important traits of the derived function is:
167128

@@ -176,31 +137,20 @@ Even though derived state is defined as functions you consume them as plain valu
176137

177138
### Dynamic getter
178139

179-
Sometimes you want to derive state based on some value coming from the user interface. You can do this by creating a function that returns a function. For example you want to be able to select records in a table and calculate some data based on that:
180-
181-
{% code title="overmind/state.ts" %}
182-
```typescript
183-
import { Derive } from 'overmind'
140+
Sometimes you want to derive state based on some value coming from the user interface. You can do this by creating a function that returns a function. This can be useful for helper functions:
184141

185-
export type State = {
186-
counts: {
187-
[id: string]: number
188-
}
189-
totalCountBy: Derive<State, (ids: string[]) => number>
190-
}
191-
192-
export const state: State = {
193-
counts: {
194-
a: 2,
195-
b: 3,
196-
c: 5
197-
},
198-
totalCountBy: state => ids => ids.reduce((aggr, id) => aggr + state.counts[id], 0)
142+
{% tabs %}
143+
{% tab title="overmind/state.js" %}
144+
```javascript
145+
export const state = {
146+
users: {},
147+
userById: ({ users }) => id => users[id]
199148
}
200149

201-
// state.totalCountBy(['a', 'b'])
150+
// state.userById('123')
202151
```
203-
{% endcode %}
152+
{% endtab %}
153+
{% endtabs %}
204154

205155
## References
206156

@@ -209,32 +159,18 @@ When you add objects and arrays to your state tree, they are labeled with an “
209159
So this is an example of how you would **not** want to do it:
210160

211161
{% tabs %}
212-
{% tab title="overmind/state.ts" %}
162+
{% tab title="overmind/state.js" %}
213163
```typescript
214-
export type User = {
215-
id: string
216-
username: string
217-
}
218-
219-
export type State = {
220-
users: {
221-
[id: string]: User
222-
}
223-
currentUser: User
224-
}
225-
226-
export const state: State = {
164+
export const state = {
227165
users: {},
228166
currentUser: null
229167
}
230168
```
231169
{% endtab %}
232170

233-
{% tab title="overmind/actions.ts" %}
171+
{% tab title="overmind/actions.js" %}
234172
```typescript
235-
import { Action } from 'overmind'
236-
237-
export const setUser: Action<string> = ({ state }, id) => {
173+
export const setUser = ({ state }, id) => {
238174
state.currentUser = state.users[id]
239175
}
240176
```
@@ -244,36 +180,21 @@ export const setUser: Action<string> = ({ state }, id) => {
244180
You’d rather have a reference to the user id, and for example use a **getter** to grab the actual user:
245181

246182
{% tabs %}
247-
{% tab title="overmind/state.ts" %}
183+
{% tab title="overmind/state.js" %}
248184
```typescript
249-
export type User = {
250-
id: string
251-
username: string
252-
}
253-
254-
export type State = {
255-
users: {
256-
[id: string]: User
257-
}
258-
currentUserId: string
259-
currentUser: User
260-
}
261-
262-
export const state: State = {
185+
export const state = {
263186
users: {},
264187
currentUserId: null,
265-
get currentUser(this: State) {
188+
get currentUser(this) {
266189
return this.users[this.currentUserId]
267190
}
268191
}
269192
```
270193
{% endtab %}
271194

272-
{% tab title="overmind/actions.ts" %}
195+
{% tab title="overmind/actions.js" %}
273196
```typescript
274-
import { Action } from 'overmind'
275-
276-
export const setUser: Action<string> = ({ state }, id) => {
197+
export const setUser = ({ state }, id) => {
277198
state.currentUserId = id
278199
}
279200
```
@@ -284,43 +205,31 @@ export const setUser: Action<string> = ({ state }, id) => {
284205

285206
We define the state of the application in **state** files. For example, the top level state could be defined as:
286207

287-
{% code title="overmind/state.ts" %}
288-
```typescript
289-
export type User = {
290-
username: string
291-
bio: string
292-
}
293-
294-
export type State = {
295-
isLoading: boolean
296-
user: User
297-
}
298-
299-
export const state: State = {
208+
{% tabs %}
209+
{% tab title="overmind/state.js" %}
210+
```javascript
211+
export const state = {
300212
isLoading: false,
301213
user: null
302214
}
303215
```
304-
{% endcode %}
216+
{% endtab %}
217+
{% endtabs %}
305218

306219
To expose the state on the instance you can follow this recommended pattern:
307220

308221
{% tabs %}
309-
{% tab title="overmind/index.ts" %}
222+
{% tab title="overmind/index.js" %}
310223
```typescript
311224
import { state } from './state'
312225

313226
export const config = {
314227
state
315228
}
316-
317-
declare module 'overmind' {
318-
interface Config extends IConfig<typeof config> {}
319-
}
320229
```
321230
{% endtab %}
322231

323-
{% tab title="index.ts" %}
232+
{% tab title="index.js" %}
324233
```typescript
325234
import { createOvermind } from 'overmind'
326235
import { config } from './overmind'
@@ -330,6 +239,10 @@ const overmind = createOvermind(config)
330239
{% endtab %}
331240
{% endtabs %}
332241

242+
{% hint style="info" %}
243+
For scalability you can define **namespaces** for multiple configurations. Read more about that in [Structuring the app](../guides-1/structuring-the-app.md)
244+
{% endhint %}
245+
333246
## Summary
334247

335248
This short guide gave you some insight into how we think about state and what state really is in an application. There is more to learn about these values and how to use them to describe the application. Please move on to other guides to learn more.

core/going-functional.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ What we see here is an action trying to express a search. We only want to search
3232
If we were to do this in a functional style it would look more like this:
3333

3434
{% tabs %}
35-
{% tab title="overmind/actions.ts" %}
35+
{% tab title="overmind/actions.js" %}
3636
```typescript
37-
import { Operator, pipe, debounce, mutate, filter } from 'overmind'
37+
import { pipe, debounce, mutate, filter } from 'overmind'
3838

39-
export const search: Operator<string> = pipe(
39+
export const search = pipe(
4040
mutate(({ state }, value) => {
4141
state.query = value
4242
}),

0 commit comments

Comments
 (0)