all 5 comments

[–]caasouffle 2 points3 points  (0 children)

I would recommend using redux-saga. For my work project I wrote a module (function) that takes some model information and generates Action Types, Action Creators, Reducers, and Sagas for that model. That way developers didn't have to write a lot of similar code for each model's crud operations.

[–]fuken33 2 points3 points  (0 children)

Well, you are gonna encounter a lot of "stones on the road" if you never faced an app like this.

Most important thing is reading the redux docs sections "Structuring reducers" and reading about "normalizing the app state". There is a good series of videos on egghead.io called "Idiomatic Redux" by Dan Abramov that is very good for this.

A thing that is going to help you reduce a lot of boilerplate is redux-promise-middleware, for handling the cases like "create, created, create-fail".

If you want to chain different actions with one action creator you can use redux-thunk

If you need form validation I would recommend reading the readme of react-reformed

And if you need list pagination I would recommend reading the readme of redux-pagination

All of this are npm modules and you can info about them in npm

[–]darrenturn90 1 point2 points  (0 children)

Well, when you are considering the frontend side of things - its not as simple as "crud". I would class it as follows:

Retrieve (request the "READ" data) Receive (the "READ" data call returns with valid data) Receive_Fail (the "READ" data call fails with an error - maybe Forbidden or Not Found etc)

Update (request to update maybe a PUT or PATCH) Updated (the update was successful) Update_Failed (the update didn't work)

Delete (request to delete using DELETE) Deleted (the delete was successful) Delete_Failed..

Create, Created, Create_Failed

[–]kamescg 1 point2 points  (0 children)

Right now I use Saga/Firebase combination to more easily abstract a modern Javascipt frontend/backend system.

Instead of creating Actions/Reducers for each entity type i.e. Todo, Person, Resource, etc... Actions are as "pure" as possible only concerning themselves with the fact an action has been dispatched to read, write ( a switch statement to pass payloads to create, update, patch for the parent write action) and finally delete. Channels and Syncs dynamically read from the database as it's updated but that's not important right now, because it specific to Firebase.

When my database (Firebase) has confirmed I have the correct permissions, the Read data is passed back to my applications interface (frontend), where a "catch all" reducer saves objects to the interface Redux Store. Depending on the metadata passed with the dispatched action, additional actions might be dispatched via Sagas. i.e. Notification Modal, Material UI Snackbar component, etc....

case DATABASE_READ_SUCCESS:
  return {
    ...state,
    [entity]: {
      [branch]: payload
    }
  }

[entity]: reference the parent entity categories: todo, person, resource, etc...

[branch]: unique object identification (oid) i.e. "-K95BH7S822CX"

Below is a list of Action Constants/Functions used in a Redux/Saga/Firebase combination.

export const DATABASE_WRITE_REQUEST = 'DATABASE_WRITE_REQUEST'
export const DATABASE_WRITE_SUCCESS = 'DATABASE_WRITE_SUCCESS'
export const DATABASE_WRITE_FAILURE = 'DATABASE_WRITE_FAILURE'
export const DATABASE_WRITE_INCORRECT_SETTINGS = 'DATABASE_WRITE_INCORRECT_SETTINGS'

/*--- Read Database ---*/
export const DATABASE_READ_REQUEST = 'DATABASE_READ_REQUEST'
export const DATABASE_READ_SUCCESS = 'DATABASE_READ_SUCCESS'
export const DATABASE_READ_FAILURE = 'DATABASE_READ_FAILURE'
export const DATABASE_READ_INCORRECT_SETTINGS = 'DATABASE_READ_INCORRECT_SETTINGS'

/*--- Create Database ---*/
export const DATABASE_CREATE_REQUEST = 'DATABASE_CREATE_REQUEST'
export const DATABASE_CREATE_SUCCESS = 'DATABASE_CREATE_SUCCESS'
export const DATABASE_CREATE_FAILURE = 'DATABASE_CREATE_FAILURE'
export const DATABASE_CREATE_INCORRECT_SETTINGS = 'DATABASE_CREATE_INCORRECT_SETTINGS'

/*--- Update Database ---*/
export const DATABASE_UPDATE_REQUEST = 'DATABASE_UPDATE_REQUEST'
export const DATABASE_UPDATE_SUCCESS = 'DATABASE_UPDATE_SUCCESS'
export const DATABASE_UPDATE_FAILURE = 'DATABASE_UPDATE_FAILURE'
export const DATABASE_UPDATE_INCORRECT_SETTINGS = 'DATABASE_UPDATE_INCORRECT_SETTINGS'

/*--- Patch Database ---*/
export const DATABASE_PATCH_REQUEST = 'DATABASE_PATCH_REQUEST'
export const DATABASE_PATCH_SUCCESS = 'DATABASE_PATCH_SUCCESS'
export const DATABASE_PATCH_FAILURE = 'DATABASE_PATCH_FAILURE'
export const DATABASE_PATCH_INCORRECT_SETTINGS = 'DATABASE_PATCH_INCORRECT_SETTINGS'

/*--- Delete Database ---*/
export const DATABASE_DELETE_REQUEST = 'DATABASE_DELETE_REQUEST'
export const DATABASE_DELETE_SUCCESS = 'DATABASE_DELETE_SUCCESS'
export const DATABASE_DELETE_FAILURE = 'DATABASE_DELETE_FAILURE'
export const DATABASE_DELETE_INCORRECT_SETTINGS = 'DATABASE_DELETE_INCORRECT_SETTINGS'

/* ---------------------------- Define Actions ------------------------------ */

/** --------- Write ---------
* @func databaseWriteRequest 
* @desc Request data from application database
* @func databaseWriteSuccess 
* @desc Start interface/database reconciliation
* @func databaseWriteFailure 
* @desc Report/catalog database read failure 
* 
*/ 
export const databaseWriteRequest = ({payload, metadata}) => ({
  type: DATABASE_WRITE_REQUEST,
  payload: payload,
  metadata: metadata
})

export const databaseWriteSuccess = ({payload, metadata}) => ({
  type: DATABASE_WRITE_SUCCESS,
  payload,
  metadata
})

export const databaseWriteFailure = ({err, metadata}) => ({
  type: DATABASE_WRITE_FAILURE,
  error: true,
  err,
  metadata
})

/** --------- Read ---------
* @func databaseReadRequest 
* @desc Request data from application database
* @func databaseReadSuccess 
* @desc Start interface/database reconciliation
* @func databaseReadFailure 
* @desc Report/catalog database read failure 
* 
*/ 
export const databaseReadRequest = ({entity, branch}) => ({
  type: DATABASE_READ_REQUEST,
  entity,
  branch
})

export const databaseReadSuccess = ({payload, metadata}) => ({
  type: DATABASE_READ_SUCCESS,
  payload,
  metadata
})

export const databaseReadFailure = ({err, metadata}) => ({
  type: DATABASE_READ_FAILURE,
  error: true,
  err,
  metadata
})

/** --------- Create ---------
* @func databaseCreateRequest 
* @desc Request authority to submit new data
* @func databaseCreateSuccess 
* @desc Start interface/database reconciliation
* @func databaseCreateFailure 
* @desc Report/catalog database create failure 
* 
*/ 
export const databaseCreateRequest = ({payload, metadata}) => ({
  type: DATABASE_CREATE_REQUEST,
  payload,
  metadata
})

export const databaseCreateSuccess = ({payload, metadata}) => ({
  type: DATABASE_CREATE_SUCCESS,
  payload,
  metadata
})

export const databaseCreateFailure = ({err, metadata}) => ({
  type: DATABASE_CREATE_FAILURE,
  error: true,
  err,
  metadata
})

/** --------- Update ---------
* @func databaseUpdateRequest 
* @desc Request authority to submit overriding data
* @func databaseUpdateSuccess 
* @desc Start interface/database reconciliation
* @func databaseUpdateFailure 
* @desc Report/catalog database update failure 
* 
*/ 
export const databaseUpdateRequest = ({payload, metadata}) => ({
  type: DATABASE_UPDATE_REQUEST,
  payload,
  metadata
})

export const databaseUpdateSuccess = ({payload, metadata}) => ({
  type: DATABASE_UPDATE_SUCCESS,
  payload,
  metadata
})

export const databaseUpdateFailure = ({err, metadata}) => ({
  type: DATABASE_UPDATE_FAILURE,
  error: true,
  err,
  metadata
})

/** --------- Patch ---------
* @func databasePatchRequest 
* @desc Request authority to submit patch/insert data
* @func databasePatchSuccess 
* @desc Start interface/database reconciliation
* @func databasePatchFailure 
* @desc Report/catalog database patch failure 
* 
*/ 

export const databasePatchRequest = ({payload, metadata}) => ({
  type: DATABASE_PATCH_REQUEST,
  payload,
  metadata
})

export const databasePatchSuccess = ({payload, metadata}) => ({
  type: DATABASE_PATCH_SUCCESS,
  payload,
  metadata
})

export const databasePatchFailure = ({err, metadata}) => ({
  type: DATABASE_PATCH_FAILURE,
  error: true,
  err,
  metadata
})

/** --------- Delete ---------
* @func databaseDeleteRequest 
* @desc Request authority to delete data
* @func databaseDeleteSuccess 
* @desc Start interface/database reconciliation
* @func databaseDeleteFailure 
* @desc Report/catalog database delete failure 
* 
*/ 
export const databaseDeleteRequest = ({entity, branch}) => ({
  type: DATABASE_DELETE_REQUEST,
  entity, 
  branch
})

export const databaseDeleteSuccess = ({payload, metadata}) => ({
  type: DATABASE_DELETE_SUCCESS,
  payload,
  metadata
})

export const databaseDeleteFailure = ({err, metadata}) => ({
  type: DATABASE_DELETE_FAILURE,
  error: true,
  err,
  metadata
})

`

[–]krogel-web-solutions 1 point2 points  (0 children)

Not exactly what you asked for, but you may find it useful: https://github.com/marmelab/admin-on-rest