|
@@ -18,15 +18,15 @@
|
|
|
* reference), but creates a modified state and returns it. Also, the reducer
|
|
|
* should return immediately. If an asynchronous operation has to be executed,
|
|
|
* it is handled through redux-sagas, which is basically a concurrent process
|
|
|
- * triggered by a reducer, which generates a new action once it's completed.
|
|
|
+ * triggered by a reducer, which generates a new action once it's completed.
|
|
|
*
|
|
|
- * Action creators (defined as 'actions' in this file) are bound to the
|
|
|
+ * Action creators (defined as 'actions' in this file) are bound to the
|
|
|
* Redux dispatcher in 'index.js'. When they are called, the dispatcher sends
|
|
|
* the greated action to **all** reducers. This module, and other modules which
|
|
|
- * change the state of this module, use these action creators to modifiy the
|
|
|
+ * change the state of this module, use these action creators to modifiy the
|
|
|
* state.
|
|
|
*
|
|
|
- * This file exports everything which is necessary to set up and operate the
|
|
|
+ * This file exports everything which is necessary to set up and operate the
|
|
|
* state of this module.
|
|
|
* - actions
|
|
|
* - reducers
|
|
@@ -34,27 +34,29 @@
|
|
|
* - sagas
|
|
|
**/
|
|
|
|
|
|
-
|
|
|
/* Import NAME and DATA to be able to create action creators */
|
|
|
import { NAME, DATA } from './constants'
|
|
|
import primary from './initialData'
|
|
|
import { delay } from 'redux-saga'
|
|
|
import { call, put, takeEvery } from 'redux-saga/effects'
|
|
|
|
|
|
-
|
|
|
/** actionTypes define what actions are handeled by the reducer. */
|
|
|
const actionTypes = {}
|
|
|
export const actionCreators = {}
|
|
|
|
|
|
// Generate default actionsTypes CREATE, UPDATE, REMOVE
|
|
|
-DATA.forEach(dataItem => {
|
|
|
+DATA.forEach((dataItem, idx) => {
|
|
|
['create', 'update', 'remove'].forEach(action => {
|
|
|
// The Redux convention is to name action types e.g. demo_module/UPDATE
|
|
|
// For action creators, we define here the name e.g. removePrimary(id, data)
|
|
|
// where id is the element id and data is the element itself.
|
|
|
const actionType = `${action.toUpperCase()}_${dataItem.toUpperCase()}`
|
|
|
- const actionName = `${action}${dataItem[0].toUpperCase()}${dataItem[0].substring(1)}`
|
|
|
- actionCreators[actionName] = (id, data) => { return { type: actionType, id, data } }
|
|
|
+ const actionName = `${action}${dataItem[0].toUpperCase()}${dataItem.substring(1)}`
|
|
|
+ if (idx === 0) {
|
|
|
+ actionCreators[actionName] = (id, data) => { return { type: `${NAME}/${actionType}`, id, data } }
|
|
|
+ } else {
|
|
|
+ actionCreators[actionName] = (primaryId, id, data) => { return { type: `${NAME}/${actionType}`, primaryId, id, data } }
|
|
|
+ }
|
|
|
actionTypes[actionType] = `${NAME}/${actionType}`
|
|
|
})
|
|
|
})
|
|
@@ -66,7 +68,7 @@ updateSecondary1 (id, data) {
|
|
|
// id is used to find the secondary item. data is the new value of the item.
|
|
|
}
|
|
|
removeSecondary2 (id, data) {
|
|
|
- // id is used to find the secondary item.
|
|
|
+ // id is used to find the secondary item.
|
|
|
}
|
|
|
*/
|
|
|
|
|
@@ -75,13 +77,11 @@ actionCreators['loadSamples'] = () => { return { type: `${NAME}/LOAD_SAMPLES` }
|
|
|
actionTypes['LOAD_SAMPLES'] = `${NAME}/LOAD_SAMPLES`
|
|
|
console.log('State actionTypes, actionCreators', actionTypes, actionCreators)
|
|
|
|
|
|
-
|
|
|
/** state definition */
|
|
|
/** It is generally easier to not have another object here. */
|
|
|
export const state = []
|
|
|
console.log('State state', state)
|
|
|
|
|
|
-
|
|
|
/** reducer is called by the redux dispatcher and handles all component actions */
|
|
|
/** The module's root reducer tries to split up the state and let specific
|
|
|
* specialized reducers handle the work. This is not necessary, but more
|
|
@@ -89,22 +89,24 @@ console.log('State state', state)
|
|
|
// In this example it is assumed, that the secondary items have a key 'primaryId',
|
|
|
// which references the primary data element.
|
|
|
export function reducer (state = [], action) {
|
|
|
+ // Return immediately, if action type doesn't match
|
|
|
+ if (typeof action.type === 'undefined' || !action.type.match(RegExp(NAME))) {
|
|
|
+ return state
|
|
|
+ }
|
|
|
// find the primary data element with the matching id.
|
|
|
- const idx = state.findIndex(elem => {return (action.id === elem.id)})
|
|
|
- console.log(`Entering demo_module root reducer.`, state, action, idx)
|
|
|
+ let idx
|
|
|
let nextState
|
|
|
+ console.log(`Entering demo_module root reducer.`, state, action, idx)
|
|
|
if (action.type.match(/SECONDARY/)) {
|
|
|
+ idx = state.findIndex(elem => { return (action.primaryId === elem.id) })
|
|
|
// leave immediately, if no idx was found (operations on secondary not valid if there's no primary)
|
|
|
if (idx < 0) {
|
|
|
return state
|
|
|
}
|
|
|
console.log(`Using secondary reducer.`)
|
|
|
- const subState = state.secondary
|
|
|
+ const subState = state[idx].secondary
|
|
|
const reducedState = secondaryReducer(subState, action)
|
|
|
- nextState = {
|
|
|
- ...state,
|
|
|
- secondary: reducedState
|
|
|
- }
|
|
|
+ nextState = [ ...state.slice(0, idx), {...state[idx], secondary: reducedState}, ...state.slice(idx + 1) ]
|
|
|
console.log('Leaving demo_module root reducer', subState, reducedState, nextState)
|
|
|
return nextState
|
|
|
}
|
|
@@ -119,7 +121,7 @@ export function reducer (state = [], action) {
|
|
|
return nextState
|
|
|
case actionTypes.REMOVE_PRIMARY:
|
|
|
console.log('wtf')
|
|
|
- nextState = [ ...state.slice(0, idx), ...state.slice(idx+1) ]
|
|
|
+ nextState = [ ...state.slice(0, idx), ...state.slice(idx + 1) ]
|
|
|
console.log('Removing primary', state, nextState)
|
|
|
return nextState
|
|
|
case actionTypes.LOAD_SAMPLES:
|
|
@@ -133,7 +135,10 @@ export function reducer (state = [], action) {
|
|
|
|
|
|
function secondaryReducer (state = [], action) {
|
|
|
console.log(`Entering secondary reducer.`, state, action)
|
|
|
- const idx = state.findIndex(elem => {return (action.id === elem.id)})
|
|
|
+ const idx = state.findIndex(elem => {
|
|
|
+ console.log('searching index', action, elem)
|
|
|
+ return (action.id === elem.id)
|
|
|
+ })
|
|
|
let nextState
|
|
|
switch (action.type) {
|
|
|
case actionTypes.CREATE_SECONDARY:
|
|
@@ -141,7 +146,7 @@ function secondaryReducer (state = [], action) {
|
|
|
console.log(`Creating secondary.`, state, nextState)
|
|
|
return nextState
|
|
|
case actionTypes.UPDATE_SECONDARY:
|
|
|
- nextState = [ ...state.slice(0, idx), action.data, ...state.slice(idx + 1)]
|
|
|
+ nextState = [ ...state.slice(0, idx), action.data, ...state.slice(idx + 1) ]
|
|
|
console.log(`Updating secondary.`, idx, state, nextState)
|
|
|
return nextState
|
|
|
case actionTypes.REMOVE_SECONDARY:
|