root-systems / dogstack

:dog: :dog: :dog: a popular-choice grab-bag framework for teams working on production web apps
https://dogstack.js.org/
25 stars 7 forks source link

dogstore #93

Open ahdinosaur opened 6 years ago

ahdinosaur commented 6 years ago

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-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:

changes:

redux-action-query

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)
    }
  }
]