|
1 | 1 | # Namespacing |
2 | 2 |
|
| 3 | +When your application grows it can be a good idea to separate your state and logic into different domains by using namespaces. An example of this is when you have an application with different pages. You might want to use each page as a namespace for state and logic. It might also make sense to have a namespace responsible for managing the data of your application, talking to the server etc. There is no one right answer here and it is up to you to define these namespaces. |
| 4 | + |
| 5 | +Instead of defining one application module exporting state, providers and actions, you can define multiple modules. |
| 6 | + |
| 7 | +{% code-tabs %} |
| 8 | +{% code-tabs-item title="app/modules/moduleA.js" %} |
| 9 | +```javascript |
| 10 | +export const state = { |
| 11 | + title: 'Page A' |
| 12 | +} |
| 13 | + |
| 14 | +export const actions = action => ({ |
| 15 | + doThis: action() |
| 16 | +}) |
| 17 | +``` |
| 18 | +{% endcode-tabs-item %} |
| 19 | + |
| 20 | +{% code-tabs-item title="app/modules/moduleB.js" %} |
| 21 | +```javascript |
| 22 | +export const state = { |
| 23 | + title: 'Page B' |
| 24 | +} |
| 25 | + |
| 26 | +export const actions = action => ({ |
| 27 | + doThis: action() |
| 28 | +}) |
| 29 | +``` |
| 30 | +{% endcode-tabs-item %} |
| 31 | + |
| 32 | +{% code-tabs-item title="app/modules/moduleA.ts" %} |
| 33 | +```typescript |
| 34 | +import { Action } from '../' |
| 35 | + |
| 36 | +type State = { |
| 37 | + title: string |
| 38 | +} |
| 39 | + |
| 40 | +export const state: State = { |
| 41 | + title: 'Page A' |
| 42 | +} |
| 43 | + |
| 44 | +export const actions = (action: Action) => ({ |
| 45 | + doThis: action() |
| 46 | +}) |
| 47 | + |
| 48 | +``` |
| 49 | +{% endcode-tabs-item %} |
| 50 | + |
| 51 | +{% code-tabs-item title="app/modules/moduleB.ts" %} |
| 52 | +```typescript |
| 53 | +import { Action } from '../' |
| 54 | + |
| 55 | +type State = { |
| 56 | + title: string |
| 57 | +} |
| 58 | + |
| 59 | +export const state: State = { |
| 60 | + title: 'Page B' |
| 61 | +} |
| 62 | + |
| 63 | +export const actions = (action: Action) => ({ |
| 64 | + doThis: action() |
| 65 | +}) |
| 66 | +``` |
| 67 | +{% endcode-tabs-item %} |
| 68 | +{% endcode-tabs %} |
| 69 | + |
| 70 | +In the main application file you will now use the **namespaces** function to define the namespaces: |
| 71 | + |
| 72 | +{% code-tabs %} |
| 73 | +{% code-tabs-item title="app/index.js" %} |
| 74 | +```javascript |
| 75 | +import App, { namespaces } from 'overmind/$VIEW' |
| 76 | +import * as moduleA from './modules/moduleA' |
| 77 | +import * as moduleB from './modules/moduleB' |
| 78 | + |
| 79 | +const config = namespaces({ |
| 80 | + moduleA, |
| 81 | + moduleB |
| 82 | +}) |
| 83 | + |
| 84 | +const app = new App(config) |
| 85 | + |
| 86 | +export const connect = app.connect |
| 87 | +``` |
| 88 | +{% endcode-tabs-item %} |
| 89 | + |
| 90 | +{% code-tabs-item title="app/index.ts" %} |
| 91 | +```typescript |
| 92 | +import App, { TConnect, TContext, IAction, namespaces } from 'overmind/$VIEW' |
| 93 | +import * as moduleA from './modules/moduleA' |
| 94 | +import * as moduleB from './modules/moduleB' |
| 95 | + |
| 96 | +const config = namespaces({ |
| 97 | + moduleA, |
| 98 | + moduleB |
| 99 | +}) |
| 100 | + |
| 101 | +export type Context = TContext<typeof config.state, typeof config.providers> |
| 102 | + |
| 103 | +export type Action = IAction<typeof config.state, Context> |
| 104 | + |
| 105 | +const app = new App(config) |
| 106 | + |
| 107 | +export type Connect = TConnect<typeof app.state, typeof app.actions> |
| 108 | + |
| 109 | +export const connect = app.connect |
| 110 | +``` |
| 111 | +{% endcode-tabs-item %} |
| 112 | +{% endcode-tabs %} |
| 113 | + |
| 114 | +Now your state, providers and actions are namespaced accordingly. Meaning that inside actions you would need to use `state.moduleA.title`and `state.moduleB.title`, the same goes for providers and actions. |
| 115 | + |
| 116 | +### Dynamic namespaces |
| 117 | + |
| 118 | +If you want to create a module that is shared between projects you want to make sure that any namespace might be used, but still be able to point correctly to state and providers inside the actions of your shared module. |
| 119 | + |
| 120 | +A module can also be defined as a function which receives the namespace: |
| 121 | + |
| 122 | +{% code-tabs %} |
| 123 | +{% code-tabs-item title="app/index.js" %} |
| 124 | +```javascript |
| 125 | +export default (namespace) => ({ |
| 126 | + state: { |
| 127 | + foo: 'bar' |
| 128 | + }, |
| 129 | + actions: action => ({ |
| 130 | + doThis: action() |
| 131 | + .map((_, context) => context[namespace].hello()) |
| 132 | + .mutation(state => state[namespace].foo = 'bar2') |
| 133 | + }), |
| 134 | + providers: { |
| 135 | + hello: () => 'hello' |
| 136 | + } |
| 137 | +}) |
| 138 | +``` |
| 139 | +{% endcode-tabs-item %} |
| 140 | + |
| 141 | +{% code-tabs-item title="app/index.ts" %} |
| 142 | +```typescript |
| 143 | +import { Namespace, IAction, TContext } from 'overmind' |
| 144 | + |
| 145 | +export default (namespace: Namespace) => { |
| 146 | + type State = { |
| 147 | + foo: string |
| 148 | + } |
| 149 | + type NamespacedState = { |
| 150 | + [namespace]: State |
| 151 | + } |
| 152 | + type NamespacedProviders = { |
| 153 | + [namespace]: typeof providers |
| 154 | + } |
| 155 | + type Context = TContext<NamespacedState, NamespacedProviders> |
| 156 | + type Action = IAction<NamespacedState, Context> |
| 157 | + |
| 158 | + const state: State = { |
| 159 | + foo: 'bar' |
| 160 | + } |
| 161 | + const providers = { |
| 162 | + hello: () => 'hello' |
| 163 | + } |
| 164 | + const actions = (action: Action) => ({ |
| 165 | + doThis: action() |
| 166 | + .map((_, context) => context[namespace].hello()) |
| 167 | + .mutation(state => state[namespace].foo = 'bar2') |
| 168 | + }) |
| 169 | + |
| 170 | + return { |
| 171 | + state, |
| 172 | + actions, |
| 173 | + providers |
| 174 | + } |
| 175 | +} |
| 176 | +``` |
| 177 | +{% endcode-tabs-item %} |
| 178 | +{% endcode-tabs %} |
| 179 | + |
| 180 | +As you can see we are actively using the passed in namespace inside the actions to look up correct state and providers. |
| 181 | + |
0 commit comments