This is probably a mistake on my part but I've noticed that in my Redux store, for every entity, there seems to be an outer object named x which in turn has a child with the same name, which then contains the data.
This is better explained with an example:
user reducer
const initialState = {
user: {},
}
const usersReducer = (state = initialState, action) => {
switch (action.type) {
case LOGIN_USER:
return {
...state,
user: action.payload,
loggedIn: true,
}
case REGISTER_USER:
return {
...state,
user: action.payload,
registered: true,
}
default:
return state
}
}
user object in state
As you can see, user has a user nested inside of it.. can this pattern be avoided somehow in the reducer?
You can change your script on
case LOGIN_USER:
return {
...state,
...action.payload,
loggedIn: true,
}
etc..
it's should help you
Related
I've been working with redux for the last couple weeks and was incorporating it into my projects when I ran into this wall. Pretty common reducer for modals being rendered so i can animate them before unmounting them.
const initialState = {
isModalOpen: false,
test: false
}
export default function(state = initialState, action) {
switch (action.type) {
case "modalInteraction":
return {
isModalOpen: action.payload
};
case "testModalInteraction":
return {
test: action.payload
};
default:
return state;
};
}
Sadly, the test property is still returning as undefined despite the fact that the other initial state in the same reducer can be called without a problem. I even removed all the testModalInteraction dispatches in the case that that somehow upset the datatype. I just can't spot the difference that keeps returning undefined.
When you return the new state, make sure to spread the initial state (...state) and then change whatever values you need to change.
const initialState = {
isModalOpen: false,
test: false
}
export default function(state = initialState, action) {
switch (action.type) {
case "modalInteraction":
return {
...state,
isModalOpen: action.payload
};
case "testModalInteraction":
return {
...state,
test: action.payload
};
default:
return state;
};
}
If it is still undefined, make sure the payloads are defined for both actions.
For example, your modalInteraction action could look like
export const modalInteraction = (bool) => ({
type: "modalInteraction",
payload: bool
})
P.S., you can destructure the action object. This allows you to use "type" instead of "action.type" and "payload" instead of "action.payload".
const initialState = {
isModalOpen: false,
test: false
}
export default function(state = initialState, action) {
const {type, payload} = action;
switch (type) {
case "modalInteraction":
return {
...state,
isModalOpen: payload
};
case "testModalInteraction":
return {
...state,
test: payload
};
default:
return state;
};
}
I would like to give more flexibility to my reducer without adding different initalstates and
cases.
I try to explain:
import {
FETCH_DB,
FETCH_CAT,
} from "../types"
// put a variable here:
const initalState = {
db: [],
categories: [], // create a dynamic state i.e. categories.VARIABLE
}
export default (state = initalState, action) => {
switch (action.type) {
case FETCH_DB:
return {
...state,
db: action.payload,
current: null,
loading: false,
}
case FETCH_CAT:
VARIABLE HERE
return {
...state,
categories[VARIABLE]: action.payload, // syntax with [] doesn't work
loading: false,
}
default:
return state
}
}
My aim is to pass a variable through out a component so I can have categories.VAR as many as I want.
Does someone know if is possible?
Thanks!
I guess it may be your solution 🙂
case FETCH_CAT:
const newState = {
...state,
loading: false
}
newState.categories[variable] = action.payload
return newState
Do
case FETCH_CAT:
return {
...state,
categories: {
...state.categories,
[variable]: action.payload
},
loading: false
}
Below is the code of my reducer. whenever I am trying to update list array it says it is not iterable. Can anyone please tell me what mistake I am doing?
initialState = {
list: [],
taskAdded: false,
taskList: ""
}
export const task = (state = initialState, action) => {
switch (action.type) {
case types.ADD_TASK:
return {
...state,
taskList: action.payload,
taskAdded: true,
list: [...state.list, action.payload]
}
case types.CLEAR_ADD_TASK_STATE:
return {
...state,
taskList: "",
taskAdded: false
}
default:
return state
}
}
When I try to call any other action in redux it is setting one part of the state to it's initialState.
My root reducer looks like this
const rootReducer = combineReducers({
credentials: combineReducers({
cred,
user,
partner,
merchant,
bank,
error,
auth,
}),
preCredentials,
theme,
});
the part of the state that is being cleared is theme.
action dispatched
state diff
Why this actions that have anything to do with theme reducer can change its state.
Theme reducer
function theme(state = { ...INITIAL_THEME }, action) {
switch (action.type) {
case LOADING_THEME:
return {
...state,
isLoading: true,
};
case SAVE_THEME:
return {
...action.theme,
error: {
status: null,
message: '',
},
isLoading: false,
};
case CLEAR_THEME:
return INITIAL_THEME;
default:
return INITIAL_THEME;
}
}
reducer of dispatched action
function preCredentials(state = { ...INITIAL_STATE }, action) {
switch (action.type) {
case SAVE_USERNAME:
return { ...state,
user: { ...state.user,
fullName: action.fullName,
},
};
default:
return state;
}
}
function theme(state = { ...INITIAL_THEME }, action) {
switch (action.type) {
case LOADING_THEME:
return {
...state,
isLoading: true,
};
case SAVE_THEME:
return {
...state,
...action.theme,
error: {
status: null,
message: '',
},
isLoading: false,
};
case CLEAR_THEME:
return INITIAL_THEME;
default:
return state;
}
}
return state instead of initial state
I'm building a quite simple app using Redux and my reducers all look alike. It works, technically, but that's a lot of code duplication.
// The employees reducer
export default (state = initialState, action) => {
switch (action.type) {
case EMPLOYEES_REQUEST:
return [ ...state, { isFetching: true } ]
case EMPLOYEES_SUCCESS:
// DEBUG
console.log('Dispatching employees');
console.log(action.response);
// END DEBUG
// Return employees directly in the employees state
return { ...state, list: JSON.parse(action.response) };
case EMPLOYEES_FAILURE:
return [ ...state, { isFetching: false } ]
default:
return state
}
}
And
// The services reducer
export default (state = initialState, action) => {
switch (action.type) {
case SERVICES_REQUEST:
return [ ...state, { isFetching: true } ]
case SERVICES_SUCCESS:
// DEBUG
console.log('Dispatching services');
console.log(action.response);
// END DEBUG
// Return services directly in the services state
return { ...state, list: JSON.parse(action.response) };
case SERVICES_FAILURE:
return [ ...state, { isFetching: false } ]
default:
return state
}
}
Is there something I can to to use a generic reducer with different actions?
Thanks!
Reducer is just a function. You could always use a higher order function to make it.
const makeListReducer = (initial, prefix) => (state = initial, action) => {
switch(action.type) {
case `${prefix}_REQUEST`: return {...state, isFetching: true}
case `${prefix}_SUCCESS`: return {...state, isFetching: false, list: JSON.parse(action.response)}
case `${prefix}_FAILURE`: return {...state, isFetching: false, /*etc*/}
}
return state
}
// The employees reducer
export default makeListReducer(initialState, 'EMPLOYEES')