Closed jesseskinner closed 8 years ago
Break chaining of actions.
Although this was an undocumented feature, I think it leaks too much about the action. It'd be nicer to be able to provide someone an action without having access to the store. But currently, you can do action = store.action; /* later */ store = action();
. Instead I think it'd be more useful to return the new state from calling an action, eg. state = store.action()
.
Add initialState
argument as 2nd argument to the Hoverboard
function.
Almost every store I've created has had the need for initial or default state. v1 allowed a getInitialState
method to achieve this. With v2 I usually solved this with an init
or set
action, and that would still be an option for doing so, but it'd be very nice to have a shortcut in the creation of a store.
Deprecating store.getState()
over store()
. These two functions do the same thing. Although the getState
method allows for cleaner code, the downside is that it's in the namespace of the actions as well, and it's not an action.
A workaround to provide this method for legacy code would be easy:
store = Hoverboard(actions);
store.getState = store;
Re-introduce the ability to return a function from an action handler in order to perform async updates.
I regret removing this ability in Hoverboard v2. My reasoning at the time was to simplify things, and it did, but it also created a circular dependency between the action handler and the store singleton. It essentially makes it impossible to have an async action handler defined in a different file from the store definition, because the action handler was forced to know about the store singleton so that it could call an action with the result from loading.
Re-introducing this feature will break any stores that keep functions as state, though I doubt this use case is very common.
The use would look like this, providing both setState and getState methods to be called at a future time.
// in actions.js, which knows nothing about store.js
export function load(state, params) {
return (setState, getState) => {
api.get('data', params).then(result =>
// here we finally merge our data into the current state
setState(Object.assign({}, getState(), { data: result }))
)
}
}
// in store.js
import { load } from './actions'
const actions = { loadData: load }
const initialState = { data: null }
const store = Hover(actions, initialState)
// this will return the current (initial) state synchronously
// we won't have the async state yet, of course
const state = store.loadData({ param: 1 })
Here are some thoughts on the next breaking changes. Mostly I want to remove magic, improve predictability and hopefully stabilize the API for the long term.
Stop merging state returned from actions.
I'm starting to regret adding magic around plain objects in Hoverboard. Magic is unpredictable, and I've even surprised myself in how it works. For example, I mistakenly thought returning nothing from an action would leave the state unmodified, but actually it wipes it out. Is this a bug or expected behaviour? Since the answer is unclear, I think the functionality needs to change to be more predictable. Although it'd take a bit more work to merge new properties into state in action handlers, at least the result will be predictable - that whatever is returned from an action handler becomes the new state.
Stop making copies of plain objects for state listeners.
Although this seems like it'd help enforce immutable data, since it only works on the shallow level, it probably gives a false sense of security. It may also cause performance and memory issues when used with a large number of subscribers and large data over frequent updates. With
Hoverboard.compose
, you should be able to wrap a store in some protection eg. useObject.freeze
.