Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New API #5

Open
usirin opened this issue Apr 9, 2016 · 1 comment
Open

New API #5

usirin opened this issue Apr 9, 2016 · 1 comment

Comments

@usirin
Copy link
Owner

usirin commented Apr 9, 2016

0.5.0 is gonna introduce a new api called createModule and it will also deprecate the NuclearModule() constructor in favor of this new api.

createModule api is the new api which will be used to create new nuclear-js modules. It introduces new type of module syntax, both in creation and after creation steps.

// modules/counter/index.js

// 0.4.0: Use `NuclearModule` constructor directly.
// All modules are anonymous (has no name) 
import NuclearModule from 'nuclear-module'
export default CounterModule = NuclerModule({ stores, actions, getters })

// 0.5.0: Use `NuclearModule.createModule()` to create modules.
// All modules has a name.
import { createModule } from 'nuclear-module'
export default CounterModule = createModule('Counter', { stores, actions, getters })
  • How stores were written in the initial releases was very different than how they are being written as regular stores in the regular nuclear-js module, we were making extra assumptions:
// modules/counter/stores/CounterStore.js

// 0.4.0: special syntax introduced for nuclear-module
export default {
  getInitialState() { return 0 },
  handlers: [
    { type: 'INCREMENT', handler(state) { return state + 1 } },
    { type: 'DECREMENT', handler(state) { return state - 1 } }
  ]
}

// 0.5.0: regular store definition syntax
export default {
  getInitialState() { return 0},
  initialize() {
    this.on('INCREMENT', (state) => state + 1)
    this.on('DECREMENT', (state) => state - 1)
  }
}
  • Full reactor instance were being injected into each action as first parameter. In 0.5.0 things are changing into a way that actions are now functions returning real actions. This is an easier and cleaner way to inject dispatch and evaluate functions to the actions. (actions SHOULD only use these 2 functions anyway, instead of passing the full reactor instance was already not necessary).
// modules/counter/actions.js

// 0.4.0: registered reactor instance is injected as first parameter to the actions.
export const increment = (reactor) => reactor.dispatch('INCREMENT')

// 0.5.0: instead of full reactor instance, only `dispatch` and `evaluate` functions will be injected.
// also the signature is changed to a function returning function
export const increment = ({ dispatch, evaluate }) => () => dispatch('INCREMENT')
  • There is no change on how you would create getters. Pass getters object to createModule() function.

These are the differences on how modules are created in 0.5.0. There is also changes on how you would use the created modules as a result from createModule() function.

  • Actions are exported as the same way: counterModule.actions.increment()
  • Registered getters will be exported as functions that will evaluate real getters
// app.js

// 0.4.0
const counter = CounterModule(reactor)
counter.actions.increment()

// use module level exported getters.
reactor.evaluate(CounterModule.getters.count)
// => 1

// 0.5.0
const counter = CounterModule(reactor)
counter.actions.increment()

// We can still use module level exported getters
reactor.evaluate(CounterModule.getters.count)
// => 1

// 0.5.0 introduces instance level getters:
counter.getters.count()
// => 1

// instance level getters are functions, which accepts an optional transform function.
counter.getters.count(count => count * 5)
// => 5
  • Before 0.5.0 nuclear-module wasn't doing anything about observers, other than simply exporting registered getters. Starting from 0.5.0 created modules will have observers property which works very similar to how instance level getters work.
// 0.4.0: use module level getters
reactor.observe(CounterModule.getters.count, (count) => console.log('count changed: %s', count))
counter.actions.increment()
// => count changed: 1

// 0.5.0: still can use module level getters to bind observers
// use instance level `observers`
counter.observers.count(count => console.log('count changed: %s', count))
counter.actions.increment()
// => count changed: 1

// with React
counter.observers.count(count => React.render(<div>{count}</div>))

Why?

Initial releases were POC, which was really simple (it was all written in ~3 hrs) which didn't cover most use cases (registering same stores multiple times, not really providing any convenience other than providing a more structural index.js for your modules, making assumptions about how stores can be registered) when writing real modules.

With 0.5.0 registered module instances will have all their needs exported (computing getter results without requiring reactor instance, binding observers without requiring reactor instance, dispatching actions without requiring reactor instance).

Removal of the need of a reactor actually opens up many doors, most importantly removal of the hard dependency of nuclear-js (Module constructor functions will now require an object which has 4 functions: dispatch, evaluate, and observe, registerStores):

interface NuclearModuleReactor {
  dispatch(actionType: string, payload: object): void;
  evaluate(getter: Getter): any;
  observe(getter: Getter, handler: function): void;
  registerStores(stores: object): void;
}

Since any Nuclear.Reactor instances will satisfy this interface, passing down your app's reactor still work quite nicely. This also opens up really nice ways to integrate with other flux/data/etc. libraries, and their modules.

  • We can compose a new dispatch function using dispatch middlewares. (Possibility to use redux middlewares)
  • We can compose a new registerStores function using registerStores middlewares. (Possibility to use redux reducers as stores)
  • We can compose a new observe function using observe middlewares. (Possibility to use RxJS observables as instance level observers)

With this release we will have the ability to use 3rd party libraries components in our reactor modules easily. Any feedback is appreciated.

@usirin
Copy link
Owner Author

usirin commented Apr 9, 2016

/cc @gaearon would love your feedback on this.

@usirin usirin changed the title Release 0.5.0 New API Apr 9, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant