Skip to content

actionsIncludingCrud

Peter Gundel edited this page Jul 21, 2017 · 2 revisions

Source

Removing reducer boilerplate for common CRUD functionality

The export actionsIncludingCrud is simply a wrapper around actions with useful defaults for CRUD functionality.

Here's an example of basic CRUD logic for a blog and how it would work using actionsIncludingCrud:

import { crudState, crudReducer } from 'redux-belt'

const actions = actionsIncludingCrud('blogpost')
const reducer = (state = crudState, action = {}) => crudReducer(state, action, actions)

export { actions, reducer }

Imagine a CreateBlogPost component, which has the generated actions connected and mapped to its props, and the part of the store controlled by the exported reducer in this.props.blogpost:

componentWillMount() {
  const { setChanges } = this.props.blogpost
  setChanges({}) // => this.props.blogpost.changes is now {}
}

updateInPlace(patch) {
  const { mergeChanges } = this.props.blogpost
  mergeChanges(patch) // => this.props.blogpost.changes would be set to { ...changes, ...patch }
}

publishBlogPost() {
  const { create, changes } = this.props.blogpost
  create(changes)
}

We could listen to the create call in a saga by using simpleAsync (some imports are missing):

import { simpleAsync } from 'redux-belt'

import { actions } from './path-to-blogpost-actions'

export const createBlogPost = makeSimpleAsync({
  apiCall: payload => [api.createBlogPost, payload],
})

export default function* blogPostSaga() {
  yield fork(takeLatest, actions.CREATE, createBlogPost)
}

With this simple set-up, when create is called from our CreateBlogPost component, the following will happen:

  1. The store will serve a loading state as this.props.blogpost.loading.create that's useful for interface changes.
  2. simpleAsync will call your api.createBlogPost function, which performs the network request and returns a promise.
  3. If the network request is successful, the saga will dispatch an action with type blogpost/CREATE_SUCCESS and the server response as a payload.
  4. If the network request fails, the saga will dispatch an action with type blogpost/CREATE_FAILURE and the server response as a payload.
  5. The reducer will listen to blogpost/CREATE_SUCCESS or blogpost/CREATE_FAILURE and set the loading.create flag to false. If successful, the changes will be reset to an empty object, and the newly created blog post will be available under this.props.blogpost.single. If the request failed, the errors will be available under this.props.blogpost.errors.

Currently, redux-belt works for the examples supplied here and for many other uses. But the API is still under consideration, so expect many breaking changes until 1.0.0.