Redux-React populate initialState with api call - reactjs

populate my initialState with json api call from a component or from here
const initialState = {
myvalues: [] ---->here i want to populate this array
};
const reducer = (state = initialState, action) => {
const newState = { ...state };
switch (action.type) {
case "Update":
console.log(newState);
// newState.myvalues = action.key.title.value;
default:
return newState;
}
};
export default reducer;

To populate your initialState with data from an API, you can create e.g. an FETCH_INIT_DATA_ACTION, which get's dispatched right after you initialised your store.
// ...
const store = createStore(/* ... */)
store.dispatch({ type: 'FETCH_INIT_DATA_ACTION' })
// ...
whereas FETCH_INIT_DATA_ACTION triggers a redux-thunk, saga, effect or whatever you want to use.

You can do it like this:
const reducer = (state = initialState, action) => {
switch (action.type) {
case "Update":
return { ...state, myvalues: action.payload }
default:
return state;
}
};
And when you dispatch it you should put your API data in 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.

React Redux Reducer does not retain other states

I am trying to use stackoverflow api to make my first react redux project. I need to maintain a state like the following:
{
selectedTag: reactjs,
selectedSortOrder: activity,
items:[]
}
My reducer is given below:
const initialState = {
selectedTag: 'C#',
selectedSortOrder: 'activity', items: []
}
function SelectTag(state = initialState, action) {
switch (action.type) {
case SELECTTAG:
// console.log(state);
return Object.assign({}, state, { selectedTag: action.selectedTag });
default:
return state;
}
}
function SelectSortOrder(state = initialState, action) {
switch (action.type) {
case SELECTSORTORDER:
//console.log(state);
return Object.assign({}, state, { selectedSortOrder: action.selectedSortOrder });
default:
return state;
}
}
function ReceivePosts(state = { items: [] }, action) {
switch
(action.type) {
case RECEIVESORTEDPOSTS:
case RECEIVEPOST:
console.log(state);
return Object.assign({}, state, { items: action.items })
default:
return state
}
}
const rootReducer = combineReducers({ ReceivePosts, SelectTag, SelectSortOrder })
And mapStateToProps is:
const mapStateToProps = (state) => {
const selectedTag = state.SelectTag.selectedTag;
const items = (state.ReceivePosts.items);
const tags = (state.ReceiveTags.tags);
const selectedSortOrder = state.SelectSortOrder.selectedSortOrder;
return {selectedTag, items, tags, selectedSortOrder};
}
I have 2 problems here:
a. State does not remember all the data. For eg. suppose I select the tag first and then get items, my state has only items. SelectedTag is not set in the state.
b. I am not sure why mapStateToProps needs the reducer name. Eg: const selectedTag = state.SelectTag.selectedTag;
Actually it should be state.selectedTag. But my code expects the reducer name "SelectTag" to fetch the state value.
What am I doing wrong?
You haven't configured your reducers correctly. The initialState is assigned to all of your reducers which isn't required
const initialState={
selectedTag:'C#',
selectedSortOrder:'activity',
items:[]
}
function SelectTag(state = initialState.selectedTag, action){
switch(action.type){
case SELECTTAG:
return action.selectedTag
default:
return state;
}
}
function SelectSortOrder(state = initialState.selectedSortOrder, action){
switch(action.type){
case SELECTSORTORDER:
return action.selectedSortOrder
default:
return state;
}
}
function ReceivePosts(state = {items:[]}, action){
switch(action.type){
case RECEIVESORTEDPOSTS:
case RECEIVEPOST:
console.log(state);
return Object.assign({}, state, {items:action.items})
default:
return state
}
}
const rootReducer = combineReducers({ReceivePosts, SelectTag, SelectSortOrder})
And in mapStateToProps you would use it like
const mapStateToProps = (state) => {
const selectedTag = state.SelectTag;
const items = (state.ReceivePosts.items);
const tags = (state.ReceiveTags.tags);
const selectedSortOrder = state.SelectSortOrder;
return {selectedTag, items, tags, selectedSortOrder};
}
1. Try this code change
const initialState = {
selectedTag: 'C#',
selectedSortOrder: 'activity',
items: []
}
function SelectTag(state = initialState.selectedTag, action) {
switch (action.type) {
case SELECT TAG:
return {
...state,
selectedTag: action.selectedTag
}
default:
return state;
}
}
function SelectSortOrder(state = initialState.selectedSortOrder, action) {
switch (action.type) {
case SELECTSORTORDER:
return {
...state,
selectedSortOrder: action.selectedSortOrder
}
default:
return state;
}
}
function ReceivePosts(state = { items: [] }, action) {
switch (action.type) {
case RECEIVESORTEDPOSTS:
case RECEIVEPOST:
return {
...state,
items: action.items
}
default:
return state
}
}
const rootReducer = combineReducers({ ReceivePosts, SelectTag, SelectSortOrder });
2. I am not sure why mapStateToProps needs the reducer name. Eg: const selectedTag = state.SelectTag.selectedTag;
Its because when you use combinereducers, you are combining multiple slices of data, then you need to specify the slice from which you want to fetch the data.
const rootReducer = combineReducers({
receivePosts = ReceivePosts,
selectTag = SelectTag,
selectSortOrder = SelectSortOrder
});
Issue: You have not configured your initialstate properly, you are using the same initialstate in SelectTag and also in SelectSortOrder, if the initial state is same then why do you need two reducers?

How do I return an array from a reducer?

I have an array of items. When the items update I dispatch an UPDATED_LIST action and pass along the item with its updated data.
For example:
const initialState = {
items: []
}
const reducer = items(state = initialState, action) {
switch(action.type) {
case 'UPDATED_ITEMS':
return { ...state, ...action.payload }
default:
return state
}
}
I dispatch like so:
store.dispatch({
type: 'UPDATED_ITEMS',
payload: [ { name: "bob"}, { name: "harry" } ]
})
And mapStateToProps:
const mapStateToProps = state => ({ items: state.items })
My problem is when I try to access items from within a component it's an object instead of an array. I have to do the following to get access to the array:
const mapStateToProps = state => ({
items: Object.keys(state.offers).map((k) => state.items[k])
})
Is it possible to get the items as an array without having to convert them?
In your reducer update it to where you set items with the action payload. You were previously using the spread operator on your action payload which converts all your array indexes into the state object as keys.
const reducer = items(state = initialState, action) {
switch(action.type) {
case 'UPDATED_ITEMS':
return { ...state, items: [...action.payload] }
default:
return state
}
}
If you don't want a nested state in your mapStateToProps you can do this where you make your initial state an array. Similar to the todo reducer shown here. https://redux.js.org/basics/example-todo-list#reducerstodos.js
const initialState = [];
const reducer = items(state = initialState, action) {
switch(action.type) {
case 'UPDATED_ITEMS':
return [ ...action.payload ];
default:
return state
}
}
const mapStateToProps = state => ({
items: state.items
})

Redux: Approach to store from reducer

I'm trying to get the store from the reducer.
i saw the redux architecture is not supporting sharing between reducers.
but its really needed in my case.
const initState = {
schemas: [],
};
const myReducer = (state , action) => {
state = state || initState;
switch (action.type) {
case 'redux-form/CHANGE':
const schemaId = getStore().context.schema;
let modifier = state.schemas.get(schemaId);
modifier[action.key] = action.value;
return {
...state
};
}
};
my app reducers:
const iceApp = combineReducers({
form: formReducer,
context,
myReducer,
});
thanks ahead.
You can add reducer functions to any level of your state, consider:
const complexReducer = (state, action) {
const {context, myReducer} = state;
switch (action.type) {
case 'redux-form/CHANGE':
// do something with myReducer
return {context, myReducer};
default:
return state;
}
}
// a simple utility function to call reducers in sequence on the same state
function composeReducers(...reducers) {
return (state, action) => reducers.reduceRight((acc, reducer) => reducer(acc, action), state);
}
const iceApp = composeReducers(complexReducer, combineReducers({
form: formReducer,
context,
myReducer,
}));
This will apply the complexReducer to the whole state coming from the simple reducers.
A different approach is to access context in the action and pass it as payload of the action.
const changeAction = ... // the redux-form/change action
const changeActionWithContext = () => (dispatch, getState) => {
const state = getState();
const schemaId = state.context.schema;
dispatch(changeAction(schemaId));
}
I don't now redux-form so I don't know whether it's possible or not to add custom payload to redux-form actions.

Resources