milankinen / ffux

[NOT MAINTAINED] Functional Reactive Flux for RxJS and Bacon.js
MIT License
72 stars 6 forks source link

Add extra parameter support to store creation #3

Closed milankinen closed 9 years ago

milankinen commented 9 years ago

Stores must have a way to receive extra parameters from the initialization code. By using these parameters, server-side rendering can mock the browser-specific stuff (like AJAX calls) that cause errors in the server

Before:

default export createStore({
  actions: ["saveToServer"],
  state: (initial, {saveToServer}) => {
    const saved = saveToServer.flatMap(item => $.ajax(...post item..)) // << depends on window
  }
})

After:

// myStore.js
default export createStore({
  actions: ["saveToServer"],
  // extra parameters available as parameter after dependencies
  state: (initial, {saveToServer}, {}, {api}) => {
    const saved = saveToServer.flatMap(item => fromPromise($.ajax(...post item...))) // << depends on window
  }
})

// store initialization
const api = { post(data) { return $.ajax(...post data...) } }
const myStore = MyStore(initialValue, {}, {api})   // extra parameters passed as a third parameter
amccloud commented 9 years ago

Did you mean this for after?

// myStore.js
default export createStore({
  actions: ["saveToServer"],
  // extra parameters available as parameter after dependencies
  state: (initial, {saveToServer}, {}, {api}) => {
    const saved = saveToServer.flatMap(item => fromPromise(api)) // << depends on window
  }
})

// store initialization
const api = { post(data) { return $.ajax(...post data...) } }
const myStore = MyStore(initialValue, {}, {api})   // extra parameters passed as a third parameter

What is the second argument {} for the store?

milankinen commented 9 years ago

Absolutely right, thanks for correcting!

The second argument is store's dependencies. I've been wondering if extras and deps could be combined into single object like this:

const Todos = createStore({
  actions: ["createItem"],
  state: (initial, {createItems}, {deps: {filter}, extras: {api}}) => {
    ...
  }
})

// store initialization
const api = { post(data) { ... } }
const filter = Filter("")
const todos = Todos([], {deps: {filter}, extras: {api}})   // vs. Todos([], {filter}, {api})

But I don't know which one would be easier to understand / use. Opinions appreciated!

amccloud commented 9 years ago

Aren't extras just dependencies?

milankinen commented 9 years ago

Now that you said it, yeah they should be! But this would require that the store instance is just an EventStream (currently they're not) that could be passed as it is. But I think that's just a good idea because it would me the API more coherent and even simpler.

milankinen commented 9 years ago

In version 0.7.0, any values can be passed as dependencies:

// myStore.js
default export createStore({
  actions: ["saveToServer"],
  // extra parameters available as parameter after dependencies
  state: (initial, {saveToServer}, {api}) => {
    const saved = saveToServer.flatMap(item => fromPromise(api.post(item)))
  }
})

// store initialization
const api = { post(data) { return $.ajax(...post data...) } }
const myStore = MyStore(initialValue, {api})

Stores are now event streams so the new implementation is backwards compatible with older versions (stores can be treated as event streams just like actions).