Loading...
+ }
+
+ if (state.current === 'AUTHENTICATED') {
+ return
+ {state.todos.current === 'LOADING' ? 'Loading...' : null}
+
{state.todos.list.map(() => ...)}
+
+ )
+}
+```
+
+## Strict mode
+
+In strict mode you are not able to change state in actions, you explicitly have to use a state machine transitions through the **send** API to make state changes.
+
+```javascript
+const overmind = createOvermind(config, {
+ strict: true
+})
+```
+
+```javascript
+export const authChanged = ({ state }, user) => {
+ // This would throw an error
+ state.user = user
+}
+```
+
diff --git a/introduction.md b/introduction.md
index 256f924..545c178 100644
--- a/introduction.md
+++ b/introduction.md
@@ -8,7 +8,7 @@ If you rather want to go right ahead and set up a local project, please have a l
Before we move on, have a quick look at this sandbox. It is a simple counter application and it gives you some foundation before talking more about Overmind and building applications.
-{% embed url="https://codesandbox.io/s/overmind-counter-c4tuh?fontsize=14&hidenavigation=1&theme=dark&view=editor&runonclick=1" %}
+{% embed url="https://codesandbox.io/s/overmind-counter-c4tuh?fontsize=14&hidenavigation=1&theme=dark&view=editor&runonclick=1" caption="" %}
## Application state VS Component state
@@ -29,7 +29,7 @@ Introducing these scenarios we said: **You want**. In reality we rarely know exa
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.
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 related to other changes, or even change it to something else.
-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”**.
+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 you are more flexible to future changes”**.
## Defining state
@@ -93,7 +93,7 @@ And as we will see later you will also be using **effects** from the context.
Now we will move to a more complex example. Please have a look:
-{% embed url="https://codesandbox.io/s/overmind-todomvc-simple-097zs?fontsize=14&hidenavigation=1&theme=dark&view=editor&runonclick=1" %}
+{% embed url="https://codesandbox.io/s/overmind-todomvc-simple-097zs?fontsize=14&hidenavigation=1&theme=dark&view=editor&runonclick=1" caption="" %}
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.
@@ -139,7 +139,7 @@ state.todos[myReference]
delete state.todos[myReference]
```
-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.
+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.
## Deriving state
@@ -149,7 +149,7 @@ Looking through the example you have probably noticed these:
createOvermind({
state: {
...,
- currentTodos: ({ todos, filter }) => {
+ currentTodos: derived(({ todos, filter }) => {
return Object.values(todos).filter(todo => {
switch (filter) {
case 'active':
@@ -160,16 +160,16 @@ createOvermind({
return true;
}
});
- },
- activeTodoCount: ({ todos }) => {
+ }),
+ activeTodoCount: derived(({ todos }) => {
return Object.values(todos).filter(todo => !todo.completed).length;
- },
- hasCompletedTodos: ({ todos }) => {
+ }),
+ hasCompletedTodos: derived(({ todos }) => {
return Object.values(todos).some(todo => todo.completed);
- },
- isAllTodosChecked: ({ currentTodos }) => {
+ }),
+ isAllTodosChecked: derived(({ currentTodos }) => {
return currentTodos.every(todo => todo.completed);
- },
+ }),
},
...
})
@@ -177,13 +177,13 @@ createOvermind({
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.
-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. The derived 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.
+By using the **derived** function exported from Overmind you can insert a function into the state tree. 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. The derived 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.
## Effects
Now let us move into an even more complex application. Here we have added **effects**. Specifically effects to handle routing, storing todos to local storage and producing unique ids for the todos. We have added an **onInitialize** hook which is a special function Overmind runs when the application starts.
-{% embed url="https://codesandbox.io/s/overmind-todomvc-2im6p?fontsize=14&hidenavigation=1&theme=dark&view=editor&runonclick=1" %}
+{% embed url="https://codesandbox.io/s/overmind-todomvc-2im6p?fontsize=14&hidenavigation=1&theme=dark&view=editor&runonclick=1" caption="" %}
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:
@@ -223,7 +223,7 @@ This argument passed is transformed into something Page can understand. What thi
Defining all the state, actions and effects on one object would not work very well for a large application. A convention in Overmind is to split these concepts into different files behind folders representing a domain of the application. In this next sandbox you can see how we split up state, actions and effects into different files. They are all exposed through a main file representing that domain, in this case “the root domain”:
-{% embed url="https://codesandbox.io/s/overmind-todomvc-split-xdh41?fontsize=14&hidenavigation=1&theme=dark&view=editor&runonclick=1" %}
+{% embed url="https://codesandbox.io/s/overmind-todomvc-split-xdh41?fontsize=14&hidenavigation=1&theme=dark&view=editor&runonclick=1" caption="" %}
Also notice that we have split up the instantiation of Overmind from the definition of the application. What this allows us to do is reuse the same application configuration for testing purposes and/or server side rendering. We separate the definition from the instantiation.
@@ -236,10 +236,10 @@ Now that we have insight into the building blocks of Overmind it is time to intr
Have a look at this new project where we have typed the application:
{% hint style="info" %}
-You have to **OPEN IN EDITOR** to get the full Typescript experience.
+You have to **OPEN SANDBOX** to get the full Typescript experience.
{% endhint %}
-{% embed url="https://codesandbox.io/s/overmind-todomvc-typescript-39h7y?fontsize=14&hidenavigation=1&theme=dark&view=editor&runonclick=1" %}
+{% embed url="https://codesandbox.io/s/overmind-todomvc-typescript-39h7y?fontsize=14&hidenavigation=1&theme=dark&view=editor&runonclick=1" caption="" %}
As you can see we only have to add an **Action** type to our functions and optionally give it an input type. This is enough for the action to give you all information about the application. Try changing some code and even add some code to see how Typescript helps you to explore the application and ensure that you implement new functionality correctly.
@@ -269,7 +269,9 @@ To learn more about Overmind and Typescript read the [TYPESCRIPT](https://www.ov
## Development tool
-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:
+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.
+
+Open the **sandbox** above and try by going to the **index.tsx** file and change:
```typescript
export const overmind = createOvermind(config, {
@@ -329,9 +331,11 @@ Our todo has been added and we can even see how the derived state was affected b
## Managing complexity
-Overmind gives you a basic foundation with its **state**, **actions** and **effects**. As mentioned previously you can split these up into multiple namespaces to organize your code. This manages the complexity of scaling. There is also a complexity of reusability and managing execution over time. The **operators** API allows you to split your logic into many different composable parts. With operators like **debounce**, **waitUntil** etc. you are able to manage execution over time. With the latest addition of **statecharts** you have the possiblity to manage the complexity of state and interaction. What interactions should be allowed in what states. And with state values as **class instances** you are able to co-locate state with logic.
+
+
+Overmind gives you a basic foundation with its **state**, **actions** and **effects**. As mentioned previously you can split these up into multiple namespaces to organize your code. This manages the complexity of scaling. There is also a complexity of reusability and managing execution over time. The **operators** API allows you to split your logic into many different composable parts. With operators like **debounce**, **waitUntil** etc. you are able to manage execution over time. With the latest addition of **statemachines** you have the possiblity to manage the complexity of state and interaction. What interactions should be allowed in what states. And with state values as **class instances** you are able to co-locate state with logic.
-The great thing about Overmind is that none of these concepts are forced upon you. If you want to build your entire app in the root namespace, only using actions, that is perfectly fine. You want to bring in operators for a single action to manage time complexity, do that. Or do you have a concept where you want to safely control what actions can run in certain states, use a statechart. Overmind just gives you tools, it is up to you to determine if they are needed or not.
+The great thing about Overmind is that none of these concepts are forced upon you. If you want to build your entire app in the root namespace, only using actions, that is perfectly fine. You want to bring in operators for a single action to manage time complexity, do that. Or do you have a concept where you want to safely control what actions can run in certain states, use a statemachines. Overmind just gives you tools, it is up to you to determine if they are needed or not.
## Moving from here
diff --git a/views/angular.md b/views/angular.md
index fa6f870..6886502 100644
--- a/views/angular.md
+++ b/views/angular.md
@@ -1,5 +1,13 @@
# Angular
+## Install
+
+```text
+npm install overmind overmind-angular
+```
+
+## Configure
+
Let us have a look at how you configure your app:
{% tabs %}
@@ -44,7 +52,6 @@ import { AppComponent } from './app.component';
]
})
export class AppModule { }
-
```
{% endtab %}
@@ -91,7 +98,6 @@ platformBrowserDynamic()
ngZone: "noop"
})
.catch(err => console.log(err));
-
```
{% endtab %}
{% endtabs %}
@@ -124,6 +130,20 @@ export class AppComponent {
You can now access the **admin** state and actions directly with **state** and **actions**.
+### Polyfill environment
+
+Angular does not inject the environment, so in your **polyfill.ts** file you have to add the following:
+
+```typescript
+import { environment } from './environments/environment';
+
+(window as any).process = {
+ env: {
+ NODE_ENV: environment.production ? 'production' : 'development'
+ },
+};
+```
+
## NgZone
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.
diff --git a/views/react.md b/views/react.md
index 6bf7ed3..1b1f00b 100644
--- a/views/react.md
+++ b/views/react.md
@@ -1,5 +1,11 @@
# React
+## Install
+
+```text
+npm install overmind overmind-react
+```
+
There are two different ways to connect Overmind to React. You can either use a traditional **Higher Order Component** or you can use the new **hooks** api to expose state and actions.
When you connect Overmind to a component you ensure that whenever any tracked state changes, only components interested in that state will re-render, and will do so “at their location in the component tree”. That means we remove a lot of unnecessary work from React. There is no reason for the whole React component tree to re-render when only one component is interested in a change.
@@ -10,7 +16,12 @@ When you connect Overmind to a component you ensure that whenever any tracked st
{% tab title="Javascript" %}
```typescript
// overmind/index.js
-import { createHook } from 'overmind-react'
+import {
+ createStateHook,
+ createActionsHook,
+ createEffectsHook,
+ createReactionHook
+} from 'overmind-react'
import { state } from './state'
import * as actions from './actions'
@@ -19,7 +30,10 @@ export const config = {
actions
}
-export const useOvermind = createHook()
+export const useState = createStateHook()
+export const useActions = createActionsHook()
+export const useEffects = createEffectsHook()
+export const useReaction = createReactionHook()
// index.js
import * as React from 'react'
@@ -39,10 +53,17 @@ render((
// components/App.jsx
import * as React from 'react'
-import { useOvermind } from '../overmind'
+import { useState, useActions, useEffects, useReaction } from '../overmind'
const App = () => {
- const { state, actions, effects, reaction } = useOvermind()
+ // General
+ const state = useState()
+ const actions = useActions()
+ const effects = useEffects()
+ const reaction = useReaction()
+ // Or be specific
+ const { isLoggedIn } = useState().auth
+ const { login, logout } = useActions().auth
return