-
Notifications
You must be signed in to change notification settings - Fork 7
Open
Description
a random idea to re-write the core of dogstack
dogstore
opinionated redux using a composition of tiny modules that do one thing well:
redux-action-registryreselect-registryredux-state-reactorin progressfeathers-action@3redux-action-query- modified
redux-thunk
redux-action-registry
no more importing redux action creators around,
dispatch an action with an action creator name and arguments,
a friendly middleware will to create and dispatch the action for you.
const { createStore, applyMiddleware } = require('redux')
const { action, middleware: actionRegistryMiddleware } = require('redux-action-registry')
const reducer = require('./reducer')
const actions = {
yoga: () => ({ type: 'YOGA' }),
eat: (food) => ({ type: 'EAT', food })
sleep: (length) => ({ type: 'SLEEP', length })
}
const store = createStore(
reducer,
applyMiddleware(
actionRegistryMiddleware(actions)
)
)
store.dispatch(action('yoga'))
store.dispatch(action('eat', 'burritos'))
store.dispatch(action('sleep', '10h))source hints:
function action (actionCreator, ...args) {
return { actionCreator, args }
}reselect-registry
no more importing reselect selectors around,
create selectors from the names of other selectors.
const _ = require('lodash')
const combineSelectors = require('reselect-registry')
const usersData = state => state.users
const thingsData = state => state.things
// reselect.createSelector
const thingsByUsers = [
'things',
things => _.groupBy(things, 'userId')
]
const users = [
'users',
'thingsByUser',
(users, thingsByUser) => {
return _.mapValues(users, user => {
const things = thingsByUser[user.id]
return _.assign(user, { things })
})
}
)
// reselect.createStructuredSelector
const usersPageProps = {
users: true
}
const selectors = combineSelectors({
usersData,
thingsData,
thingsByUsers,
users,
usersPageProps
})
redux-state-reactor
reactors are similar to selectors,
they receive the state and return either an action or false.
const { createStore, applyMiddleware } = require('redux')
const { middleware: actionReactorMiddleware } = require('redux-action-reactor')
const actions = require('./actions')
const reducer = (state = {}, action) => {
if (action.type === 'AUTHENTICATE_START') {
return Object.assign(state, { isAuthenticating: true })
} else if (action.type === 'AUTHENTICATE_COMPLETE') {
return Object.assign(state, { isAuthenticating: false, isAuthenticated: true })
}
/* ... */
}
const authenticationReactor = state => {
if (state.isAuthenticated) return false
if (state.isAuthenticating) return false // to avoid reactor cycle
return actions.authenticate()
}
const reactors = [
authenticateReactor
]
const store = createStore(
reducer,
applyMiddleware(
actionReactorMiddleware(authenticationReactor)
)
)
// with empty state, will automatically start authenticating!feathers-action@3
good ideas from feathers-action@2:
- keep all request state in
featherskey - design for testing
changes:
- id of request is hash of arguments
- use
feathers-thunkinstead ofredux-observable - service method call api
- things.get(id, params), etc
- return promises
- service listener api
- things.onCreated({ dispatch, filter })
- listeners are implicitly restricted by feathers channels
- filter using similar techniques as
feathers-reactive
redux-action-query
- smart dependent queries
- assume request state is stored in
stateKey- status
- start
- error
- done
- result
- error
- status
const actions = require('./actions')
const queries = [
{
name: 'users',
action: (state) => actions.fetchUsers()
}
{
name: 'thingsForUsers',
dependencies: [
'users'
],
action: (state) => {
const users = state.users
return action.fetchThingsForUsers(users)
}
}
]
Metadata
Metadata
Assignees
Labels
No labels