I build an app in React with Redux and I try to send to my state an object and I try to save it in 'thisUser' but I don't know how to write that 'return' because mine doesn't work.
My Redux state:
const initialState = {
thisUser: {}
}
export function usersReducer(state = initialState, action) {
switch (action.type) {
case 'users/addUser':
return { ...state, thisUser: { ...state.thisUser, ...action.payload} } //the problem
default:
return state
}
}
Dispatch method:
dispatch({ type: "users/addUser", payload: new_user });
Can you tell me how to write that return, please?
If you want to append new user then why are you using object type. You should use Array Type thisUser.
const initialState = {
thisUser: []
}
export function usersReducer(state = initialState, action) {
switch (action.type) {
case 'users/addUser':
return { ...state, thisUser: [ ...state.thisUser,action.payload ] }
default:
return state
}
}
Or
If you want to save only single user object then change only that line in your code:
return { ...state, thisUser: action.payload }
It's better to use an array type for if you have a list of users .
If you have a case when you need to use an object just change the brackets [ ] on my code to curly braces { } .
const initialState = {
thisUser: [],
}
export function usersReducer(state = initialState, action) {
switch (action.type) {
case 'users/addUser':
return { ...state, thisUser: [ ...state.thisUser, ...action.payload]}
default:
return state
}
}
Related
Is it correct if we use CONSTANT which was imported and added inside of this reducer?
import { SOME_CONST } from './SOME_CONST'
export const reducer = (state = {}, action) {
switch (action.type) {
case types.SOME_TYPE:
return {
...state,
key: SOME_CONST,
}
default:
return state
}
}
It's correct. See the official shopping-cart example. They import the action type constants and use them in reducers. A key principle is that the reducer must be kept pure and idempotent.
import {
ADD_TO_CART,
CHECKOUT_REQUEST,
CHECKOUT_FAILURE
} from '../constants/ActionTypes'
const initialState = {
addedIds: [],
quantityById: {}
}
const addedIds = (state = initialState.addedIds, action) => {
switch (action.type) {
case ADD_TO_CART:
if (state.indexOf(action.productId) !== -1) {
return state
}
return [ ...state, action.productId ]
default:
return state
}
}
// ...
I am working on a React application and I am using Redux to store the state. I have the following code:
menu.reducer.js:
import { GET_MENU } from './menu.types';
const INITIAL_STATE = []
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case GET_MENU:
return [ ...action.payload ];
default:
return state;
}
}
menu.actions.js:
import { apiUrl, apiConfig } from '../../util/api';
import { GET_MENU } from './menu.types';
export const getMenu = () => async dispatch => {
const response = await fetch(`${apiUrl}/menu`);
if (response.ok) {
const menuData = await response.json();
dispatch({ type: GET_MENU, payload: menuData })
}
}
In the above Reducer, the initial state is an empty array. Dispatching the GET_MENU action, changes the initial state so that it contains an array of menu items instead.
The array that is fetched in the GET_MENU action is of the following:
However I want my initial state to be like the following:
const INITIAL_STATE = {
menuArray = [],
isSending = false
}
In the GET_MENU case in the reducer code, I am not sure what the correct syntax is to use in order to assign the menuArray property in the state to the array that is returned from the GET_MENU action.
Any insights are appreciated.
The state is simply a JavaScript value. If you want it to be an object with two properties, this isn't the right syntax:
const INITIAL_STATE = {
menuArray = [],
isSending = false
}
This is:
const INITIAL_STATE = {
menuArray: [],
isSending: false
}
Your reducer will now need to also return objects. You'll want to return a new object each time. Here's how you can do your reducer, specifically:
import { GET_MENU } from './menu.types';
const INITIAL_STATE = {
menuArray: [],
isSending: false
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case GET_MENU:
return { ...state, menuArray: [...action.payload] };
default:
return state;
}
}
This says "create an object comprised of all the properties of the previous state but with the menuArray property set to the payload."
import { GET_MENU } from './menu.types';
const initialState= {
menuArray: [],
isSending: false
}
export default (state = initialState, action) => {
switch (action.type) {
case GET_MENU:
return {...state, menuArray: action.payload};
default:
return state;
}
}
import { GET_MENU } from './menu.types';
const INITIAL_STATE = {
menuArray: [],
isSending: false
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case GET_MENU:
return {
...state,
menuArray: action.payload
};
default:
return state;
}
}
I am using redux with react and I am trying to append my array of objects gotten from my api to my redux state which is an array of objects
This is my reducer...
import { GET_BOOKS } from "../actions/types";
const initialState = {
books: [
0:{},
1:{},
]
};
export default function(state = initialState, action) {
switch (action.type) {
case GET_BOOKS:
console.log(action.payload.results);
return { ...state };
default:
return state;
}
}
My api is returning
results : [
0: {somevalue},
1: {somevalue}
]
I dont know how to spread the values into a new array.
Simply assign the property and it will overwrite the old one.
export default function(state = initialState, action) {
switch (action.type) {
case GET_BOOKS:
console.log(action.payload.results);
// spread current state and inaddition to that set new books data
// which overwrites books property from old state
return { ...state, books : action.payload.results };
// spread --^^^^^^^^^^^^^^^^^^^^^^^^^^^---
default:
return state;
}
}
UPDATE : If you want to concatenate it with existing then do something like this.
export default function(state = initialState, action) {
switch (action.type) {
case GET_BOOKS:
console.log(action.payload.results);
return { ...state, books : [...state.books, ...action.payload.results] };
default:
return state;
}
}
FYI : The ...state part is for copying other state properties(assumes there exists other state values)
You need to concat current state and data coming from api
return { books: [...state.books, ...action.payload.results] };
Complete Code
import { GET_BOOKS } from "../actions/types";
const initialState = { books: [] };
export default (state: Object = initialState, action: Object) => {
switch (action.type) {
case GET_BOOKS:
return { books: [...state.books, ...action.payload.results] };
default:
return state;
}
};
I have below actions and reducer:
actions:
import { OPEN_NODE, CLOSE_NODE, GET_NODES } from '../constants/NodeActionTypes';
export function openNode(path) {
return {
type: OPEN_NODE,
path: path
};
}
export function closeNode() {
return {
type: CLOSE_NODE
};
}
export function getNodes(path) {
return {
type: GET_NODES,
path: path
};
}
reducer:
export default function opener(state = initialState, action) {
switch (action.type) {
case OPEN_NODE:
var { path } = action
var {nodes} = getFileList(path)
return {
...state,
open:true,
nodes:nodes
};
case CLOSE_NODE:
return {
...state,
open:false
};
case GET_NODES:
var { path } = action
var {nodes} = getFileList(path)
return {
...state,
nodes:nodes
};
default:
return state;
}
}
Obviously, OPEN_NODE contain GET_NODES (only plus open:true), but there seems many way to organize the code:
pack GET_NODES reducer to a function, call this in OPEN_NODE , and add open:true.
modify openNode action, send [OPEN_NODE, GET_NODES] together , but how to write switch(action.type)'s case ?
let OPEN_NODE reducer dispatch a getNodes action to trigger GET_NODES reducer
which is best ? Or any another better way?
You don't have to keep everything inside your switch statement. If you have 2 similar actions, just refactor into a private function and call it.
In your case, it might be something like:
// your reducer helper
const getNodes = (state) => {
var { path } = action
var {nodes} = getFileList(path)
return {
...state,
nodes:nodes
};
};
// your reducer function
export default function opener(state = initialState, action) {
switch (action.type) {
case OPEN_NODE:
return { ...getNodes(state), open:true };
case GET_NODES:
return getNodes(state);
// ....
}
You can simply use the switch statement to execute both actions :
export default function opener(state = initialState, action) {
switch (action.type) {
case OPEN_NODE:
case GET_NODES:
var { path } = action
var {nodes} = getFileList(path)
return {
...state,
nodes:nodes
open: action.type === OPEN_NODE ? true : state.open
};
case CLOSE_NODE:
return {
...state,
open:false
};
default:
return state;
}
}
Check out my github project for creating generic reducers. The solution I purpose will address many of the concerns you currently have.
Redux-Reducer-Generator
I am using redux wth reactjs.
I want to store simple key/value pairs but can't get the reducer syntax right.
In this case each key/value pair will hold a connection to an external system.
Is this the right way to do it? I'm at the beginning with redux so it's a bit of mystery.
export default (state = {}, action) => {
switch(action.type) {
case 'addConnection':
return {
connections: {
...state.connections, {
action.compositeKey: action.connection
}
}
default:
return state
}
}
This worked for me:
export default (state = {}, action) => {
switch(action.type) {
case 'addConnection':
return {
...state,
connections: {
...state.connections,
[action.compositeKey]: action.connection
}
}
default:
return state
}
}
From the docs:
https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns#correct-approach-copying-all-levels-of-nested-data
You just have a couple mistakes with {} instead of [] and forgetting to use Object.assign.
const reducer = (state = {}, action) => {
switch (action.type) {
case 'addConnection':
return Object.assign({}, state, {
connections: [
...state.connections,
{
[actions.compositeKey]: action.connection
}
]
});
default:
return state;
}
}
export default reducer;
It might help to see it expressed this way too. It does the same thing but I think it reads a little nicer
const reducer = (state = {}, {type, compositeKey, connection}) => {
switch (type) {
case 'addConnection':
return Object.assign({}, state, {
connections: state.connections.concat({
[compositeKey]: connection
})
});
default:
return state;
}
}
export default reducer;
Or if you're using Immutable, something like this
import Immutable from 'immutable';
const reducer = (state = Immutable.Map(), {type, compositeKey, connection}) => {
switch (type) {
case 'addConnection':
return state.set(
'connections',
state.get('connections').concat({
[compositeKey]: connection
})
);
default:
return state;
}
}
export default reducer;
This may work
const reducer = (state = {}, {type, compositeKey, connection}) => {
switch (type) {
case 'addConnection':
var newData={};
newData[compositeKey]=connection;
return Object.assign({}, state, newData)
});
default:
return state;
}
}
export default reducer;