Skip to content

Commit 6f3ecd7

Browse files
christianalfonigitbook-bot
authored andcommitted
GitBook: [master] 10 pages modified
1 parent 0df64bd commit 6f3ecd7

File tree

8 files changed

+151
-68
lines changed

8 files changed

+151
-68
lines changed

SUMMARY.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* [Effects](core/running-side-effects.md)
1717
* [Operators](core/going-functional.md)
1818
* [Statecharts](core/statecharts.md)
19-
* [Server Side Rendering](guides-1/server-side-rendering.md)
19+
* [Server Side Rendering](core/server-side-rendering.md)
2020
* [Typescript](core/typescript.md)
2121

2222
## views
@@ -36,7 +36,7 @@
3636
* [Managing lists](guides-1/managing-lists.md)
3737
* [State first routing](guides-1/state-first-routing.md)
3838
* [Move to Typescript](guides-1/move-to-typescript.md)
39-
* [Testing](features/testing.md)
39+
* [Testing](guides-1/testing.md)
4040

4141
## API <a id="api-1"></a>
4242

core/running-side-effects.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ It can be a good idea to not allow your side effects to initialize when they are
9191
```typescript
9292
import * as firebase from 'firebase'
9393

94+
// We use IIFE to hide the private "app" variable
9495
export const api = (() => {
9596
let app
9697

@@ -132,6 +133,35 @@ export const onInitialize = async ({ effects }) => {
132133
Typically you explicitly communicate with effects from actions, by calling methods. But sometimes you need effects to know about the state of the application, or maybe some internal state in the effect should be exposed on your application state. Again we can take advantage of an **initialize** method on the effect:
133134

134135
{% tabs %}
136+
{% tab title="overmind/effects.js" %}
137+
```javascript
138+
// We use an IIFE to isolate some variables
139+
export const socket = (() => {
140+
_options
141+
_ws
142+
return {
143+
initialize(options) {
144+
_options = options
145+
_ws = new WebSocket('ws://...')
146+
_ws.onclose = () => options.onStatusChange('close')
147+
_ws.onopen = () => options.onStatusChange('open')
148+
_ws.addEventListener(
149+
'message',
150+
(event) => options.onMessage(event.data)
151+
)
152+
},
153+
send(type, data) {
154+
_ws.postMessage({
155+
type,
156+
data,
157+
token: _options.getToken()
158+
})
159+
}
160+
}
161+
})()
162+
```
163+
{% endtab %}
164+
135165
{% tab title="overmind/onInitialize.js" %}
136166
```typescript
137167
export const onInitialize = async ({ state, effects, actions }) => {
Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Here we only export the configuration from the main Overmind file. The instantia
3636

3737
## Preparing effects
3838

39-
The effects will also be shared with the server. Typically this is not an issue, but you should be careful about creating effects that run logic when they are defined. You might also consider lazy-loading effects so that you avoid loading them on the server at all. You can read more about them in [EFFECTS](../core/running-side-effects.md).
39+
The effects will also be shared with the server. Typically this is not an issue, but you should be careful about creating effects that run logic when they are defined. You might also consider lazy-loading effects so that you avoid loading them on the server at all. You can read more about them in [EFFECTS](running-side-effects.md).
4040

4141
## Rendering on the server
4242

@@ -103,3 +103,55 @@ export const onInitialize: OnInitialize = ({ state }) => {
103103
If you are using state first routing, make sure you prevent the router from firing off the initial route, as this is not needed.
104104
{% endhint %}
105105

106+
## OnInitialize
107+
108+
The `onInitialized` action does not run on the server. The reason is that it is considered a side effect you might not want to run, so we do not force it. If you do want to run an action as Overmind fires up both on the client and the server you can rather create a custom action for it.
109+
110+
{% tabs %}
111+
{% tab title="overmind/actions.js" %}
112+
```javascript
113+
export const initialize = () => {
114+
// Whatever...
115+
}
116+
```
117+
{% endtab %}
118+
119+
{% tab title="client/index.js" %}
120+
```typescript
121+
import { createOvermind } from 'overmind'
122+
import { config } from './overmind'
123+
124+
const overmind = createOvermind(config)
125+
overmind.actions.initialize()
126+
```
127+
{% endtab %}
128+
129+
{% tab title="server/index.js" %}
130+
```javascript
131+
import { createOvermindSSR } from 'overmind'
132+
import { config } from '../client/overmind'
133+
134+
export default async (req, res) => {
135+
const overmind = createOvermindSSR(config)
136+
await overmind.actions.initialize()
137+
138+
const html = renderToString(
139+
// Whatever implementation your view layer provides
140+
)
141+
142+
res.send(`
143+
<html>
144+
<body>
145+
<div id="app">${html}</div>
146+
<script>
147+
window.__OVERMIND_MUTATIONS = ${JSON.stringify(overmind.hydrate())}
148+
</script>
149+
<script src="/scripts/app.js"></script>
150+
</body>
151+
</html>
152+
`)
153+
}
154+
```
155+
{% endtab %}
156+
{% endtabs %}
157+

core/typescript.md

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,41 @@ export const filterAwesome: <T extends { isAwesome: boolean }>() => Operator<T>
387387

388388
That means this operator can handle any type that matches an **isAwesome** property, though will pass the original type through.
389389

390-
## Statecharts
390+
## Statemachine
391+
392+
Statemachines exposes a type called **Statemachine** which you will give a single type argument of what states it should manage:
393+
394+
{% tabs %}
395+
{% tab title="overmind/state.ts" %}
396+
```typescript
397+
import { Statemachine, statemachine } from 'overmind'
398+
399+
type Mode =
400+
| 'unauthenticated'
401+
| 'authenticating'
402+
| 'authenticated'
403+
| 'unauthenticating'
404+
405+
type State = {
406+
mode: Statemachine<Mode>
407+
}
408+
409+
export const state: State = {
410+
mode: statemachine<Mode>({
411+
initial: 'unauthenticated',
412+
states: {
413+
unauthenticated: ['authenticating'],
414+
authenticating: ['unauthenticated', 'authenticated'],
415+
authenticated: ['unauthenticating'],
416+
unauthenticating: ['unauthenticated', 'authenticated']
417+
}
418+
})
419+
}
420+
```
421+
{% endtab %}
422+
{% endtabs %}
423+
424+
## Statechart
391425

392426
To type a statechart you use the **Statechart** type:
393427

faq.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,9 @@ First… try to refresh your app to reconnect. If this does not work make sure t
88

99
Restart VS Code
1010

11+
## My operator actions are not running?
12+
13+
Operators are identified with a Symbol. If you happen to use Overmind across packages you might be running two versions of Overmind. The same goes for core package and view package installed out of version sync. Make sure you are only running on package of Overmind by looking into your **node\_modules** folder.
14+
1115

1216

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,18 @@ You can also do **unit testing** of actions and effects. This will cover expecte
1111
When you write tests you will create many instances of a mocked version of Overmind with the configuration you have created. To ensure that this configuration can be used many times we have to separate our configuration from the instantiation of the actual app.
1212

1313
{% tabs %}
14-
{% tab title="overmind/index.ts" %}
14+
{% tab title="overmind/index.js" %}
1515
```typescript
1616
import { IConfig } from 'overmind'
1717
import { state } from './state'
1818

1919
export const config = {
2020
state
2121
}
22-
23-
declare module 'overmind' {
24-
interface Config extends IConfig<typeof config> {}
25-
}
2622
```
2723
{% endtab %}
2824

29-
{% tab title="index.ts" %}
25+
{% tab title="index.js" %}
3026
```typescript
3127
import { createOvermind } from 'overmind'
3228
import { config } from './overmind'
@@ -43,11 +39,9 @@ Now we are free to import our configuration without touching the application ins
4339
When testing an action you’ll want to verify that changes to state are performed as expected. To give you the best possible testing experience Overmind comes with a mocking tool called **createOvermindMock**. It takes your application configuration and allows you to run actions as if they were run from components.
4440

4541
{% tabs %}
46-
{% tab title="overmind/actions.ts" %}
42+
{% tab title="overmind/actions.js" %}
4743
```typescript
48-
import { AsyncAction } from 'overmind'
49-
50-
export const getPost: AsyncAction<string> = async ({ state, api }, id) {
44+
export const getPost = async ({ state, api }, id) {
5145
state.isLoadingPost = true
5246
try {
5347
state.currentPost = await api.getPost(id)
@@ -63,7 +57,7 @@ export const getPost: AsyncAction<string> = async ({ state, api }, id) {
6357
You might want to test if a thrown error is handled correctly here. This is an example of how you could do that:
6458

6559
{% tabs %}
66-
{% tab title="overmind/actions.test.ts" %}
60+
{% tab title="overmind/actions.test.js" %}
6761
```typescript
6862
import { createOvermindMock } from 'overmind'
6963
import { config } from './'
@@ -114,7 +108,7 @@ If your actions can result in multiple scenarios a unit test is beneficial. But
114108
You do not have to explicitly write the expected state. You can also use for example [JEST](https://www.overmindjs.org/guides/intermediate/05_writingtests?view=react&typescript=true) for snapshot testing. The mock instance has a list of mutations performed. This is perfect for snapshot testing.
115109

116110
{% tabs %}
117-
{% tab title="overmind/actions.test.ts" %}
111+
{% tab title="overmind/actions.test.js" %}
118112
```typescript
119113
import { createOvermindMock } from 'overmind'
120114
import { config } from './'
@@ -162,7 +156,7 @@ In this scenario we would also ensure that the **isLoadingPost** state indeed fl
162156
The **onInitialize** hook will not trigger during testing. To test this action you have to trigger it yourself.
163157

164158
{% tabs %}
165-
{% tab title="overmind/onInitialize.test.ts" %}
159+
{% tab title="overmind/onInitialize.test.js" %}
166160
```typescript
167161
import { createOvermindMock } from 'overmind'
168162
import { config } from './'
@@ -197,29 +191,17 @@ A simple example of this is doing requests. Maybe you want to use e.g. [AXIOS](h
197191
This is just an example showing you how you can structure your code for optimal testability. You might prefer a different approach or maybe rely on integration tests for this. No worries, you do what makes most sense for your application:
198192

199193
{% tabs %}
200-
{% tab title="overmind/effects.ts" %}
194+
{% tab title="overmind/effects.js" %}
201195
```typescript
202196
import * as axios from 'axios'
203-
import { Post } from './state'
204-
205-
interface IRequest {
206-
get<T>(url: string): Promise<T>
207-
}
208-
209-
interface IOptions {
210-
authToken: string
211-
baseUrl: string
212-
}
213197

214198
// This is the class we can create new instances of when testing
215199
export class Api {
216-
request: IRequest
217-
options: IOptions
218-
constructor(request: IRequest, options: IOptions) {
200+
constructor(request, options) {
219201
this.request = request
220202
this.options = options
221203
}
222-
async getPost(id: string): Promise<Post> {
204+
async getPost(id: string) {
223205
try {
224206
const response = await this.request.get(this.options.baseUrl + '/posts/' + id, {
225207
headers: {
@@ -247,7 +229,7 @@ export const api = new Api(axios, {
247229
Let’s see how you could write a test for it:
248230

249231
{% tabs %}
250-
{% tab title="overmind/effects.test.ts" %}
232+
{% tab title="overmind/effects.test.js" %}
251233
```typescript
252234
import { Api } from './effects'
253235

quickstart.md

Lines changed: 11 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const state = {
3535
```
3636
{% endtab %}
3737

38-
{% tab title="overmind/index.ts" %}
38+
{% tab title="overmind/index.js" %}
3939
```typescript
4040
import { state } from './state'
4141

@@ -44,41 +44,20 @@ export const config = {
4444
}
4545
```
4646
{% endtab %}
47-
{% endtabs %}
48-
49-
And fire up your application in the browser or whatever environment your user interface is to be consumed in by the users.
50-
51-
### VS Code
52-
53-
For the best experience you should install the [OVERMIND DEVTOOLS](https://marketplace.visualstudio.com/items?itemName=christianalfoni.overmind-devtools-vscode) extension. This will allow you to work on your application without leaving the IDE at all.
54-
55-
![](.gitbook/assets/amazing_devtools.png)
56-
57-
{% hint style="info" %}
58-
If you are using the **Insiders** version of VSCode the extension will not work. It seems to be some extra security setting.
59-
{% endhint %}
60-
61-
### Devtool app
6247

63-
Alternatively you can install the standalone application of the devtools. It is highly recommended to install the package [CONCURRENTLY](https://www.npmjs.com/package/concurrently). It allows you to start the devtools as you start your build process:
48+
{% tab title="index.js" %}
49+
```typescript
50+
import { createOvermind } from 'overmind'
51+
import { config } from './overmind'
6452

65-
```text
66-
npm install overmind-devtools concurrently
53+
const overmind = createOvermind(config)
6754
```
55+
{% endtab %}
56+
{% endtabs %}
6857

69-
{% code title="package.json" %}
70-
```javascript
71-
{
72-
...
73-
"scripts": {
74-
"start": "concurrently \"overmind-devtools\" \"someBuildTool\""
75-
},
76-
...
77-
}
78-
```
79-
{% endcode %}
58+
And fire up your application in the browser or whatever environment your user interface is to be consumed in by the users.
8059

81-
### Hot Module Replacement <a id="quickstart-hot-module-replacement"></a>
60+
Move on with the specific view layer of choice to connect your app:
8261

83-
A popular concept introduced by Webpack is [HMR](https://webpack.js.org/concepts/hot-module-replacement/). It allows you to make changes to your code without having to refresh. Overmind automatically supports HMR. That means when **HMR** is activated Overmind will make sure it updates and manages its state, actions and effects. Even the devtools will be updated as you make changes.
62+
\*\*\*\*[**REACT** ](views/react.md)**-** [**ANGULAR**](views/angular.md) **-** [**VUE**](views/vue.md)\*\*\*\*
8463

views/angular.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import { AppComponent } from './app.component';
3939
declarations: [ AppComponent ],
4040
bootstrap: [ AppComponent ],
4141
providers: [
42-
{ provide: OVERMIND_INSTANCE, useValue: createOvermind(config) },
42+
{ provide: OVERMIND_INSTANCE, useFactory: () => createOvermind(config) },
4343
{ provide: Store, useExisting: OvermindService }
4444
]
4545
})
@@ -85,7 +85,9 @@ if (environment.production) {
8585
platformBrowserDynamic()
8686
.bootstrapModule(AppModule, {
8787
// We do not need zones, we rather use the tracking
88-
// directive, which gives us a huge optimization
88+
// directive, which gives us a pretty signifcant performance
89+
// boost. Note that 3rd party libraries might need ngZone,
90+
// in which case you can not set it to "noop"
8991
ngZone: "noop"
9092
})
9193
.catch(err => console.log(err));
@@ -124,7 +126,7 @@ You can now access the **admin** state and actions directly with **state** and *
124126

125127
## NgZone
126128

127-
Since Overmind knows when your components should update you can safely turn **ngZone** to `"noop"`. Note that other 3rd party libraries may not support this.
129+
The Overmind **\*track** directive knows when your components should update, and so is much more efficient at change detection than Angular's default NgZone. In order to take advantage of the efficiency provided by the \***track** directive, you _must_ set **ngZone** to "noop". Note that other 3rd party libraries may not support this. If for any reason you can't set **ngZone** to "noop", then the \***track** directive is redundant, and you can safely exclude it from your templates.
128130

129131
## Rendering
130132

0 commit comments

Comments
 (0)