Created
May 25, 2018 03:18
-
-
Save bradennapier/f111a9789b19e491380c98b6401faf4c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import createState from './src/libraries/state-modules/core'; | |
/* | |
Called to build our states schema. | |
*/ | |
const $ = createState({ | |
/* `config` to configure globally - passed to all state modules */ | |
config: {}, | |
/* Hooks are middleware that are called at specific parts of the lifecycle and allow modifying behavior */ | |
hooks: { | |
// Before a dispatch receives `action => mutatedAction` | |
before: [ | |
action => { | |
console.group('DISPATCHING: ', action); | |
}, | |
], | |
// After a dispatch (handled by all modules) | |
after: [ | |
() => { | |
console.groupEnd(); | |
}, | |
], | |
change: [ | |
(prevState, nextState, changed) => { | |
console.group('Changed State!'); | |
console.log(' --> \n', prevState, '\n --> \n', nextState); | |
console.log('Changed: ', changed); | |
console.groupEnd(); | |
}, | |
], | |
// When an error occurs - receives detailed information on errors | |
error: [ | |
e => { | |
console.error('ERROR: ', e.message); | |
}, | |
], | |
// When a state module loads (whether async or synchronously) | |
// load: new Set(), | |
}, | |
/* Define and provide "global selectors" used to combine data from multiple state selectors */ | |
selectors: { | |
countObj: state => ({ | |
count: state.counter.count, | |
lastSet: state.settings.lastCounterSet, | |
}), | |
}, | |
}); | |
/* | |
State Modules may also be defined with subsets of the overall options. They do not need to actually operate on | |
any state. | |
*/ | |
$.create({ | |
config: { | |
pid: 'app', | |
prefix: 'APP', | |
}, | |
actions: { | |
/* dispatches APP_READY */ | |
ready: null, | |
}, | |
}); | |
$.create({ | |
config: { | |
pid: 'something', | |
}, | |
routes: { | |
test: 'handleTestAction', | |
}, | |
sagas: { | |
async handleTestAction(action, produce, lock) { | |
// lock(); | |
// console.log('Count: ', this.getState().counter.count); | |
await this.actions.counter.decrement(); | |
// console.log('Count: ', this.getState().counter.count); | |
}, | |
}, | |
actions: { | |
test: null, | |
}, | |
}); | |
$.create({ | |
config: { | |
pid: 'counter', | |
/* Prefixes all types with COUNTER_ when defined */ | |
prefix: 'COUNTER', | |
/* Asynchronously loads the scope and runs the process when APP_READY is dispatched */ | |
loadsOnAction: 'APP_READY', | |
/* We can also use a function here */ | |
// loadsOnAction: action => action.type === 'APP_READY' | |
}, | |
/* Asynchronously loaded Scope - loaded before the initial hook */ | |
// Available as this.scope to any functions called | |
// scope: () => import('./scope'), | |
/* Extend the Core Schema - Will error if collides with another value */ | |
state: { | |
counter: { | |
count: 0, | |
}, | |
/* When keys collide on a common state value, they are merged. Collissions on defined keys will provide errors. */ | |
settings: { | |
lastCounterSet: 0, | |
}, | |
}, | |
actions: { | |
set: ['to'], | |
increment: ['by'], | |
decrement: ['by'], | |
doIncrement: ['by'], | |
}, | |
/* routes allows you to create side effects for various dispatched actions, these will call your sagas based on the route given */ | |
routes: { | |
doIncrement: 'handleIncrement', | |
}, | |
/* All state is immutable by default. "Mutating" in a reducer is not mutating our actual state, but simply a "draft" state */ | |
// * Since state is immutable across the board, if the actual values do not change while reduced, our components will not re-render | |
reducers: { | |
SET: (action, state) => { | |
state.counter.count = action.to; | |
state.settings.lastCounterSet = Date.now(); | |
}, | |
DECREMENT: (action, state) => { | |
// console.log('Decrement'); | |
state.counter.count -= action.by || 1; | |
state.settings.lastCounterSet = Date.now(); | |
}, | |
INCREMENT: (action, state) => { | |
state.counter.count += action.by || 1; | |
state.settings.lastCounterSet = Date.now(); | |
}, | |
}, | |
/* Sagas allow us to handle side effects that need to occur before state can be updated */ | |
// * Additionally, certain keys can be defined to hook into a state modules lifecycle | |
sagas: { | |
* starts() { | |
console.log('APP_READY Received: Counter Process Starts'); | |
}, | |
// Taking the second argument indicates that we need to read and/or mutate the state. | |
// Mutating the provided state object will create an "update" event. | |
async handleIncrement(action) { | |
console.log('Doing An Increment!'); | |
await this.actions.counter.increment(action.by || 1); | |
}, | |
}, | |
/* Selectors are used to provide components with simple imported pieces of the state */ | |
selectors: { | |
count: state => state.counter.count, | |
lastSet: state => state.settings.lastCounterSet, | |
}, | |
}); | |
// console.log($); | |
$.actions.app | |
.ready() | |
.then(() => $.actions.counter.decrement()) | |
.then(() => $.actions.counter.doIncrement()) | |
.then(() => $.actions.counter.doIncrement()) | |
.then(() => $.actions.counter.doIncrement()) | |
.then(() => $.actions.something.test()) | |
.catch(err => { | |
console.error('Fail: ', err); | |
}); | |
// console.log($.state); | |
console.log($); | |
setTimeout(() => { | |
console.log($.select('count')); | |
}, 5000); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment