React-Redux add new value to the state - reactjs

I am having a two step form in react. The first step of the form we ask some information to the user and then I add it to the state. The second step of the form I ask some more information to the user and add it to the state, so instead of appending the information that was asked on step 2 of the form, it overrides the state, so the state now only the info that was asked in the step 2 of the form. How can I add the have both the information together. When i try to ...state it gives me error as state is not iterable.
const infoReducer = (state = {}, action) => {
switch(action.type) {
case 'STEP_1':
return action.payload
case 'STEP_2':
return action.payload
default:
return state
}
}

check this out
import { ActionTypes } from "../../Constant/ActionType";
const initState = {
Auth: {},
};
const AuthReducer = (state = initState, action) => {
switch (action.type) {
case ActionTypes.AuthUser:
return {
...state,
Auth: action.payload,
};
default:
return state;
}
};
export default AuthReducer;

first, copy the current state data and add a new action payload as second parameter
case 'ADD_Data':
return {...state,action.payload}

Related

Can we change array stored in Redux?

I have a product filter array which i stored in redux, initially its an empty array and i want to dispatching an object in it one by one .
The issue is i want to check if the object_id is already is in the array then i don't want to dispatch it and as well as delete that particular object in redux state.
Likewise,
if user added blue color filter so its accept but if user again added blue color filter so its shouldn't dispatch this object and also remove this object in redux.
reducer:
filterd :[]
const filterreducer = (state = initialState, action) => {
switch (action.type) {
case ADD_FILTER:
return {
...state,
filterd :[...state.filterd,action.payload]
};
default:
return state;
}
}
export default filterreducer ;
initialState ={
filterd :[]
}
const filterreducer = (state = initialState, action) => { switch (action.type) {
case ADD_FILTER:
return {
...state,
filterd :action.paylod
};
default:
return state;
}
}
export default filterreducer ;
you have to store response data in payload while dispatching that action
such as:
dispatch({
type:ADD_FILTER,
payload: response.data
)

Setting the initial state of redux in reducers

Hey guys i am stuck in a situation in which i have to set the inital state of reducer to some value let me show you the code
First of all i have an action creater like this
export const fetchuser = () => {
return async dispatch => {
const res = await axios.get("/api/currentuser");
dispatch({
type: "fetchuser",
payload: res.data
});
};
};
which just fetches the data from api and dispatches an action to reducer
export default function(state = {}, action) {
switch (action.type) {
case "fetchuser":
return action.payload||false;
default:
return state;
}
}
now in second action creater i have to make a post request and increase the "credits" value in user database
export const handletoken = token => {
return async dispatch => {
const res = await axios.post("/api/stripe", token);
dispatch({ type: "credits", payload: res.data });
};
};
so i get the updated value here then i pass this on to the reducer
export default function(state = {}, action) {
switch (action.type) {
case "credits":
return action.payload
default:
return state;
}
}
and then combine them in reducer/index.js
export default combineReducers({
auth: authreducer,
credits:creditsreducer
});
console log of auth reducer in app.js in mapstatetoprops function gives
auth:
credits: 40
googleid: "109463598810933991924"
__v: 0
_id: "5d7fff2c4cb0604139055ce4"
so in credits reducer as u can see i have defined initial value of state as an empty object but i want to set it as the value of credits key of auth reducer, I could easily set it to array or an object hardcoding it but here i need to set its value as a value which is already in my another reducer so how can i achieve this ?
Assuming you need to wait for "fetchuser" to succeed to set credits in your creditsreducer you can handle the "fetchuser" action in your creditsreducer as well:
export default function(state = {}, action) {
switch (action.type) {
case "fetchuser":
return action.payload ? action.payload.credits : state;
case "credits":
return action.payload
default:
return state;
}
}
Always keep previous reducer state value. Otherwise no use of redux state value. like this
1.export default function(state = {}, action) {
switch (action.type) {
case "fetchuser":
let data = action.payload||false;
return {
...state,
fetchuser: data //any where you can access fetchuser data as well as previous state will not change.
}
default:
return state;
}
}
Change all the reducers like above.

Reducer always returning initial state

I have been playing with react-native and redux and I have encountered an error. The state is always initialised as the starting one although the payload is present when I debug it inside the reducer.
This is my reducer file
let initialState = {
filterList: [],
isFetching: false,
activeFilters: [],
}
export function fetchFilterList(state = initialState, action) {
return { ...state, isFetching: true };
}
export function fetchFilterListSuccess(state, action) {
return {
...state,
filterList: action.payload,
isFetching: true,
dsad: "dada",
}
}
export function fetchFilterListError(state, action) {
return { ...state, isFetching: false };
}
This is where I combine them into one function(in the same file as above):
export function combinedFiltersReducers(state = initialState, action) {
switch (action.type) {
case ACTION_TYPES.FETCH_FILTER_LIST:
return fetchFilterList(state, action);
case ACTION_TYPES.FETCH_FILTER_LIST_SUCCESS:
return fetchFilterListSuccess(state, action);
case ACTION_TYPES.TOGGLE_FILTER_ITEM:
return toggleFilterItemStart(state, action);
case ACTION_TYPES.TOGGLE_FILTER_ITEM_SUCCESS:
return toggleFilterItemSuccess(state, action);
default:
return state;
}
}
This is my combine reducers function in a separate file called main reducers.
export default combineReducers({
adList: fetchAdListSuccess,
filterList: combinedFiltersReducers,
});
Here is the where I receive the state in the component, and it always falls to the initial state.
const mapStateToProps = state => ({
filterList: state.filterList,
});
const mapPropsToDispatch = dispatch => ({
fetchFilterList:() => dispatch(fetchFilterList()),
toggleFilterItem: (data) => dispatch(toggleFilterItem(data)),
});
export default connect(
mapStateToProps,
mapPropsToDispatch
)(FilterComponent);
I can not find the error, so I need a bit of help. Thanks in advance.
Okay, I have found an issue. Taking an example:
return fetchFilterList(state, action);
You're calling fetchFilterList method and passing initial state. So every time you call it actually passes the initial state. And that method is just copying the initial state. Rather do like this:
return fetchFilterList(...state, action);
I am going to assume that your ACTION_TYPES do not have the appropriate type(s) for the function you are calling so it is reverting to the default case.

Passing redux state to reducer

I'm trying to delete an element from dom by clicking on it. I did it without the problem without redux thunk but now I have a problem. My reducer doesn't know about the state. How do let him know what items are?
Action:
export function deleteItem(index) {
return {
type: 'DELETE_ITEM',
index
};
}
My reducer that shows undefined.
export function deleteItem(state = [], action) {
switch (action.type) {
case 'DELETE_ITEM':
const copy = state.items.slice()
console.log(copy)
default:
return state;
}
}
Heres my actual code https://github.com/KamilStaszewski/flashcards/tree/develop/src
I saw your code and you are defining a new reducer for each of the operations you want to get done to your items (e.i itemsHaveError, deleteItem, ...) but the correct way of doing this is to store all of the relevant functions for the items to a single reducer which holds the data needed to change whenever some action to the items happens, but in the way you did it, any time any action happens because your reducers are separated the initial state gets empty as you have passed to the functions and the reducers do not know about their related data so they overwrite them with the empty initial state, the correct way would be like this to write a single reducer for items:
const initialState = {
isLoading: false,
hasError: false,
items: [],
};
export default function(state = initialState, action) {
switch (action.type) {
case ITEMS_HAVE_ERROR:
return {
...state,
hasError: action.hasError,
};
case ITEMS_ARE_LOADING:
return {
...state,
isLoading: action.isLoading,
};
case ITEMS_FETCH_DATA_SUCCESS:
return {
...state,
items: action.items,
};
case DELETE_ITEM:
const copy = state.items.slice()
return {
...state,
items: copy,
};
default:
return state;
}
}
so this would be your item.js and your item reducer and the only one that should get to combineReducer function.
Indicate the initial State of the reducer by default , the state is an empty array and you can't access the state.items , cause it is undefined. Assume this:
const x = [];
x.foo.slice();
that would return an error . Thus from :
state = []
change it to :
state = {
items:[]
}
applying it to your code:
export function deleteItem(
state = {
items:[]
},
action) {
switch (action.type) {
case 'DELETE_ITEM':
const copy = state.items.slice()
console.log(copy)
default:
return state;
}
}

How to keep dry code with reducers?

Currently I have to call three different api end points to get the information for some dropdown in a redux form.
The question I have is atm to get the end points into separate sets of state. I currently have three different reduces being imported into the index reducer so I can have them under three state terms. I have nearly the same code in three files:
//reducer/job-board/job_tools
import {FETCH_JOB_TOOLS} from "../../actions/job_list_actions";
export default function(state = {}, action) {
switch(action.type) {
case FETCH_JOB_TOOLS:
return action.payload.data;
default:
return state;
}
}
////reducer/job-board/job_roles
import {FETCH_JOB_ROLES} from "../../actions/job_list_actions";
export default function(state = {}, action) {
switch(action.type) {
case FETCH_JOB_ROLES:
return action.payload.data;
default:
return state;
}
}
Seeing as this code is nearly identical is there a way for me to dry this up and still keep three separate pieces of s
Pleas help.
Thank you.
You can do a FETCH_JOB action and pass job_type from action parameter. So you'll have one unique fetch function in reducer and you'll provide what you're fetching, this should be the key in state for what you're fetching.
store = { roles: [], tools: [] }
your reducer will looks like:
import {FETCH_JOB} from "../../actions/job_list";
export default function(state = {}, action) {
switch(action.type) {
case FETCH_JOB:
return {
...state,
[action.job_type]: action.payload.data
}
default:
return {...state};
}
}
note: in this case, it's important to generate a new state with { ...state, [...] } instead of just mutate the previous one.
By the way, I am using an array like syntax instead of switch case.
you can use a function to create reducers and provide array containing handlers.
import createReducer from './createReducer';
const loginReceived = (state, action) => ({
...state,
authData: action.auth
});
// [...]
const ACTION_HANDLERS = {
[AUTH_LOGIN_START]: loginStarted,
[AUTH_LOGIN_COMPLETE]: loginReceived,
[AUTH_LOGIN_FAIL]: loginFail
};
export default createReducer(initialState, ACTION_HANDLERS);
and use this as createReducer function
/**
* Creates a reducer.
* #param {string} initialState - The initial state for this reducer.
* #param {object} handlers - Keys are action types (strings), values are reducers (functions).
* #return {object} A reducer object.
*/
export default (initialState = null, handlers = {}) => (state = initialState, action) => {
if (!action && !action.type) return state;
const handler = handlers[action.type];
return handler && handler(state, action) || state;
};

Resources