You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: packages/overmind-website/src/components/Introduction/introduction.md
+26-22Lines changed: 26 additions & 22 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# Welcome to Overmind
2
2
3
-
In this introduction you will get an overview of Overmind and how you can think about application development. We will be using [React](https://reactjs.org/) to write the UI, but you can use also use Overmind with [Vue](https://vuejs.org/) and [Angular](https://angular.io).
3
+
In this introduction you will get an overview of Overmind and how you can think about application development. We will be using [React](https://reactjs.org/) to write the UI, but you can use Overmind with [Vue](https://vuejs.org/) and [Angular](https://angular.io) if either of those is your preference.
4
4
5
5
```marksy
6
6
h(Notice, null, "If you rather want to go right ahead and set up a local project, please have a look at the [quickstart](/guides/beginner/01_quickstart) guide.")
@@ -21,20 +21,20 @@ First of all we have to talk about **application** and **component** state. In t
21
21
22
22
If the count example above was the entire application it would not make any sense to introduce application state and Overmind. But if you were to increase the scope of this simple application you would be surprised how quickly you get into the following scenarios:
23
23
24
-
1.**You want to introduce an other component that needs to know about the current state of the count.** This new component can not be a parent of the component owning the count state. It can not be a sibling either. It has to be a child. If it is not an immediate child the count state has to be passed down the componen tree until it reaches your new component.
24
+
1.**You want to introduce an other component that needs to know about the current state of the count.** This new component can not be a parent of the component owning the count state. It can not be a sibling either. It has to be a child. If it is not an immediate child the count state has to be passed down the component tree until it reaches your new component.
25
25
2.**You want to remember the count, even though it is not shown in the UI**. Your count is behind one of multiple tabs in the UI. When the user changes the tabs you do not want the count to reset. The only way to ensure this is to move the count state up to a parent component that is no longer a child of the tab and then pass the count state back down again.
26
-
3.**You want to change the count from a side effect**. You have a websocket connection which changes the count when a message is received. If you want to avoid this websocket connection to open and close as the component mounts and unmounts you will have to move the websocket connection and count state up the component tree.
27
-
4.**You want to change the count as part of a flow**. When you click the increase count button you need to change both the count state and an other state related to a different part of the UI. To able able to change both states at the same time they have to live inside the same component, which has to be a parent of both components using the state.
26
+
3.**You want to change the count from a side effect**. You have a websocket connection which changes the count when a message is received. If you want to avoid this websocket connection to open and close as the component mounts and unmounts you will have to move the websocket connection up the component tree.
27
+
4.**You want to change the count as part of a flow**. When you click the increase count button you need to change both the count state and an other state related to a different part of the UI. To be able to change both states at the same time, they have to live inside the same component, which has to be a parent of both components using the state.
28
28
29
-
Introducing these scenarios we said: **You want**. In reality we rarely know exactly what we want. We do not know how our state and components will evolve. And this is the most important point. By using application state instead of component state you get flexibility to manage whatever comes down the road.
29
+
Introducing these scenarios we said: **You want**. In reality we rarely know exactly what we want. We do not know how our state and components will evolve. And this is the most important point. By using application state instead of component state you get flexibility to manage whatever comes down the road without having to refactor wrong assumptions.
30
30
31
-
**So is component state bad?**. No, certainly not. You do not want to overload your application state with state that could just as well have been component state. The tricky thing is to figure out when that is absolutely the case. For example:
31
+
**So is component state bad?** No, certainly not. You do not want to overload your application state with state that could just as well have been component state. The tricky thing is to figure out when that is absolutely the case. For example:
32
32
33
-
1.**Modals should certainly be component state?**. Not all modals are triggered by a user interaction. A profile modal might be triggered by clicking a profile picture, but also open up when a user opens the application and is missing information.
34
-
2.**The active tab should certainly be component state?**. The active tab might be part of the url query, `/user?tab=count`. That means it should rather be a hyperlink where your application handles the routing and provides state to identify the active tab.
35
-
3.**Inputs should certainly be component state?**. If the input is part of an application wide flow, you might want to empty out the content of that input, or even change it to something else.
33
+
1.**Modals should certainly be component state?** Not all modals are triggered by a user interaction. A profile modal might be triggered by clicking a profile picture, but also open up when a user opens the application and is missing information.
34
+
2.**The active tab should certainly be component state?** The active tab might be part of the url query, `/user?tab=count`. That means it should rather be a hyperlink where your application handles the routing and provides state to identify the active tab.
35
+
3.**Inputs should certainly be component state?** If the input is part of an application flow, you might want to empty out the content of that input, or even change it to something else.
36
36
37
-
How you want to go about this is totally up to you. We are not telling you exactly how to separate application and component state. What we can say though; **"If you lean towards application state your are more flexible to future changes"**.
37
+
How you want to go about this is totally up to you. We are not telling you exactly how to separate application and component state. What we can tell you though; **"If you lean towards application state your are more flexible to future changes"**.
38
38
39
39
## Defining state
40
40
@@ -51,7 +51,7 @@ createOvermind({
51
51
52
52
This state object will hold all the application state, we call it a *single state tree*. That does not mean you define all the state in one file and we will talk more about that later. For now lets talk about what you put into this state tree.
53
53
54
-
A single state tree favours serializable state. That means state that can be `JSON.parse` and `JSON.stringify` back and forth. Which means it can be safely passed between the client and the server, localStorage or to web workers. That means you will use **strings**, **numbers**, **booleans**, **arrays**, **objects** and **null**. Overmind does not prevent you from using other complex objects, but it is encouraged to use these core data types.
54
+
A single state tree favours serializable state. That means state that can be `JSON.parse` and `JSON.stringify` back and forth. It can be safely passed between the client and the server, localStorage or to web workers. You will use **strings**, **numbers**, **booleans**, **arrays**, **objects** and **null**. Overmind does not prevent you from using other complex objects, but it is encouraged to use these core data types.
55
55
56
56
## Defining actions
57
57
@@ -105,7 +105,7 @@ h(Sandbox, {
105
105
})
106
106
```
107
107
108
-
We have now separated out the Overmind related logic into its own file, **app.js**. This file creates the Overmind instance and also exports how the components will interact with the state and the actions.
108
+
We have now separated out the Overmind related logic into its own file, **app.js**. This file creates the Overmind instance and also exports how the components will interact with the state and the actions, the hook called **useApp**. Vue and Angular has other mechanisms conventional to those frameworks where application state and actions can be accessed.
109
109
110
110
## References
111
111
@@ -149,7 +149,7 @@ state.todos[myReference]
149
149
deletestate.todos[myReference]
150
150
```
151
151
152
-
Using references also ensures that only one instance of any todo will live in your state tree. The todo itself lives on the **todos**object, while everything else in the state tree references a todo by using its id. For example our **editingTodoId** state uses the id of a todo to reference which todo is currently being edited.
152
+
Using references also ensures that only one instance of any todo will live in your state tree. The todo itself lives on the **todos**state, while everything else in the state tree references a todo by using its id. For example our **editingTodoId** state uses the id of a todo to reference which todo is currently being edited.
153
153
154
154
## Deriving state
155
155
@@ -185,7 +185,7 @@ createOvermind({
185
185
})
186
186
```
187
187
188
-
Our state tree is concerned with state values that you will change using actions. But you can also automatically produce state values based on existing state. An example of this would be to list the **currentTodos**. It uses the todos and filter state to figure out what todos to actually display. Sometimes this is called computed values.
188
+
Our state tree is concerned with state values that you will change using actions. But you can also automatically produce state values based on existing state. An example of this would be to list the **currentTodos**. It uses the todos and filter state to figure out what todos to actually display. Sometimes this is called computed state. We call it **derived** state.
189
189
190
190
Any function you insert into the state tree is treated as derived state. That means these functions receives a preset first argument which is the immediate state, the state object the derived is attached to. In bigger applications you might also need to use the second argument, which is the root state of the application. It will automatically track whatever state you use and then flag itself as dirty whenever it changes. If derived state is used while being dirty, the function will run again. If it is not dirty a cached value is returned.
191
191
@@ -200,7 +200,7 @@ h(Sandbox, {
200
200
})
201
201
```
202
202
203
-
You can think of effects as a contract between your application and the outside world. You write an API of **what** your application needs and some 3rd party tool or native JavaScript API will implement **how** to provide it. Let us look at the router:
203
+
You can think of effects as a contract between your application and the outside world. You write an effect API of **what** your application needs and some 3rd party tool or native JavaScript API will implement **how** to provide it. Let us look at the router:
204
204
205
205
```ts
206
206
createOvermind({
@@ -222,7 +222,7 @@ createOvermind({
222
222
})
223
223
```
224
224
225
-
The router uses the [Page](https://www.npmjs.com/package/page) tool to manage routing. It takes a "url to action" option that makes sense for this application, but you could define this however you wanted:
225
+
The router uses the [Page](https://www.npmjs.com/package/page) tool to manage routing. It takes a "url to action" option that makes sense for this application, but you could define this however you wanted.
226
226
227
227
```ts
228
228
effects.router.initialize({
@@ -232,7 +232,7 @@ effects.router.initialize({
232
232
});
233
233
```
234
234
235
-
This option is transformed into something Page can understand. What this means is that we can easily switch out Page with some other tool later if we wanted to, or maybe if you app ran in different environments you could change out the implementation of the router dynamically. We were also able to combine **page** and **page.start** behind one method, which cleans up our application code. We did the same for the **storage** effect. We use localStorage and JSON.parse/JSON.stringify behind a single method.
235
+
This argument passed is transformed into something Page can understand. What this means is that we can easily switch out Page with some other tool later if we wanted to, or maybe if the app ran in different environments you could change out the implementation of the router dynamically. We were also able to combine **page** and **page.start** behind one method, which cleans up our application code. We did the same for the **storage** effect. We use localStorage and JSON.parse/JSON.stringify behind a single method.
236
236
237
237
## Scaling up the application
238
238
@@ -294,7 +294,7 @@ To learn more about Overmind and Typescript read the [Typescript](/guides/beginn
294
294
295
295
## Development tool
296
296
297
-
Overmind also ships with its own development tool. It can be installed as a [VSCode plugin](https://marketplace.visualstudio.com/items?itemName=christianalfoni.overmind-devtools-vscode) or installed as an NPM package. The development tool knows everything about what is happening inside the application. It shows you all the state, running actions and connected components. By default Overmind connects automatically to the development if it is running. Try now by going to the **index.tsx** file and change:
297
+
Overmind also ships with its own development tool. It can be installed as a [VSCode plugin](https://marketplace.visualstudio.com/items?itemName=christianalfoni.overmind-devtools-vscode) or installed as an NPM package. The development tool knows everything about what is happening inside the application. It shows you all the state, running actions and connected components. By default Overmind connects automatically to the devtool if it is running. Try now by going to the **index.tsx** file and change:
Now go to your terminal and use the NPM executor to instantly fire up the development tool:
313
+
Go to your terminal and use the NPM executor to instantly fire up the development tool.
314
314
315
315
```
316
316
npx overmind-devtools
317
317
```
318
318
319
-
Refresh the sandbox preview and you should now see the devtools populated with information from the application.
319
+
Refresh the sandbox preview and you should see the devtools populated with information from the application.
320
320
321
321
```marksy
322
322
h(Notice, null, "This only works in **CHROME** when running on codesandbox.io, due to domain security restrictions. It works on all browsers when running your project locally.")
@@ -328,7 +328,11 @@ Here we get an overview of the current state of the application, including our d
328
328
329
329

330
330
331
-
Here we can see that we grabbing todos from local storage and initializing our router. We can also see that the router instantly fires off our **changeFilter** action causing a state change on the filter. At the end we can see that our reaction triggered, saving the todos as we did update that state during the execution of this action.
331
+
Here we can see that we grabbing todos from local storage and initializing our router. We can also see that the router instantly fires off our **changeFilter** action causing a state change on the filter. At the end we can see that our reaction triggered, saving the todos.
332
+
333
+
```marksy
334
+
h(Notice, null, "You might wonder why the reaction triggered when it was defined after we changed the **todos** state. Overmind batches up changes to state and *flushes* at optimal points in the execution. For example when an action ends or some asynchronous code starts running. The reaction reacts to these flushes, just like components do.")
335
+
```
332
336
333
337
Moving on we also get insight into components looking at our application state:
334
338
@@ -350,6 +354,6 @@ Our todo has been added and we can even see how the derived state was affected b
350
354
351
355
## Moving from here
352
356
353
-
I hope this introduction got you excited about developing applications and working with Overmind. From this point you can continue working with [codesandbox.io](https://codesandbox.io) or set up a local development flow. It is highly encouraged to use Overmind with Typescript, it does not get any more complex than what you see in this simple TodoMvc application.
357
+
We hope this introduction got you excited about developing applications and working with Overmind. From this point you can continue working with [codesandbox.io](https://codesandbox.io) or set up a local development flow. It is highly encouraged to use Overmind with Typescript, it does not get any more complex than what you see in this simple TodoMvc application.
354
358
355
359
Move over to the [quickstart](/guides/beginner/01_quickstart) to get help setting up your project. The other guides will give you a deeper understanding of how Overmind works. If you are lost please talk to us on [discord](https://discord.gg/YKw9Kd) and we are happy to help. And yeah... have fun! :-)
0 commit comments