Reducer is not adding object to array, null is added instead - javascript

For practice with Redux, I have in index.js
const state = [
{
resort: 'Jay Peak',
date: '2018-2-22',
powder: true,
backcountry: false,
},
];
const action = {
type: constants.ADD_DAY,
payload: {
resort: 'Mad River Glen',
date: '2018-3-14',
powder: true,
backcountry: false,
},
};
const nextState = allSkiDays(state, action);
console.log(`
initial state: ${JSON.stringify(state)}
action: ${JSON.stringify(action)}
new state: ${JSON.stringify(nextState)}
`);
and my reducers for composition,
export const skiDay = (state = [], action) => {
action.type === constants.ADD_DAY ? action.payload : state;
};
export const allSkiDays = (state = [], action) => {
switch (action.type) {
case constants.ADD_DAY:
return [...state, skiDay(null, action)]; // COMPOSITION!!!! use skiDay()
default:
return state;
}
};
and I keep getting this result,
initial state: [{"resort":"Jay Peak","date":"2018-2-22","powder":true,"backcountry":false}]
action: {"type":"ADD_DAY","payload":{"resort":"Mad River Glen","date":"2018-3-14","powder":true,"backcountry":false}}
new state: [{"resort":"Jay Peak","date":"2018-2-22","powder":true,"backcountry":false},null]
I've tried many things why is null still being spread onto the array and not the new object?

This reducer is not returning the next state.
export const skiDay = (state = [], action) => {
action.type === constants.ADD_DAY ? action.payload : state;
};
Do this instead:
export const skiDay = (state = [], action) => {
return action.type === constants.ADD_DAY ? action.payload : state;
};

Related

How to update an array using redux reducer, I want to change a boolean property inside an array of objects to make i true or false

I have an array, every time I fire an action it adds a new item in the array with the value true and or false, I need to change that code to return the real number of the array not adding new items
Here is my code,
import {ads} from '../../data/ads';
import {ADD_TO_FAVORITE} from '../types';
interface ActionInter {
type: string;
payload: {id: number};
}
const initialState = {
allAds: ads,
myFavorite: [],
};
const myFavorite = (state = initialState, action: ActionInter) => {
switch (action.type) {
case ADD_TO_FAVORITE:
const itemFav = state.allAds[action.payload.id - 1].isFav;
console.log(itemFav);
if (itemFav === true)
return {
...state,
allAds: [
...state.allAds,
(state.allAds[action.payload.id - 1].isFav = false),
],
};
if (itemFav === false)
return {
...state,
allAds: [
...state.allAds,
(state.allAds[action.payload.id - 1].isFav = true),
],
};
}
return state;
};
export default myFavorite;
ads, it's an array of objects
You can using map like this:
const myFavorite = (state = initialState, action: ActionInter) => {
switch (action.type) {
case ADD_TO_FAVORITE:
return {
...state,
allAds: state.allAds.map((item, index) => {
return action.payload.id - 1 === index
? {
...item,
isFav: !item.isFav,
}
: item;
}),
};
}
return state;
};
You can try this:
const myFavorite = (state = initialState, action: ActionInter) => {
switch (action.type) {
case ADD_TO_FAVORITE:
const index = action.payload.id - 1;
const newAllAds = [...state.allAds];
newAllAds[index].isFav = !newAllAds[index].isFav;
return {
...state,
allAds: newAllAds,
};
}
return state;
};
You have to use immutability, instead of updating the previous state, create a copy and update that copy
const myFavorite = (state = initialState, action: ActionInter) => {
switch (action.type) {
case ADD_TO_FAVORITE: {
// Using the spread operator we'll create a copy
const allAdsCopy = [...state.allAds];
// Identify the item index
const index = action.payload.id -1;
// Update the copy
allAdsCopy[index].isFav = !allAdsCopy[index].isFav;
return {
...state,
allAds : allAdsCopy,
};
}
default:
return state;
}
};

React component not getting redux's initial state set by reducer

While creating the reducer, i have set the initial state but while loading the component for the first time, i am getting an empty state.
reducer file -
const initialValues = { geo: { latitude: 0, longitude: 0 } }
const emp = (state = initialValues, action) => {
switch (action.type) {
case 'bike': {
return { ...state, data: action.payload }
}
case 'car': {
return { ...state, headers: action.payload }
}
default:
return state
}
}
component file-
export default function Emp() {
const emp = useSelector(state => state)
console.log('emp state', emp)
}
index.js
const store = createStore(reducer,
{},
compose(
applyMiddleware(
loggingMiddleware,
),
window.devToolsExtension ? window.devToolsExtension() : f => f
)
)
I got the solution. Actually i was not using combine reducer before thats why reducer's state was not getting initialized.

React Redux reducer not Updating State

So I have a reducer which doesn't seem to be updating the state at all whenever I called the 'LOGIN' action. It could be a problem with my React Redux code. It's either my component is not getting re rendered whenever the store's state changes or the reducer is not changing the stores state at all.
Reducer ------
const initialState = {
messages: [],
loginDetails: {
email: '',
password: ''
},
activeUsers: [],
loginActive: false
}
const messageReducer = (state = initialState, action) => {
switch(action.type) {
case 'ADD_MESSAGE':
if(state.messages.length < 50) {
let newStateMessages = [...state.messages]
newStateMessages.unshift(action.payload);
console.log(newStateMessages);
return {...state, messages: newStateMessages};
} else {
let newStateMessages = [...state.messages]
newStateMessages.pop();
newStateMessages.unshift(action.payload);
return {...state, newStateMessages};
}
case 'LOGIN':
console.log('LOGIN');
console.log(action);
const newLoginDetails = {
email: action.payload.email,
password: action.payload.password
};
console.log({...state, loginDetails: newLoginDetails});
return {...state, loginDetails: newLoginDetails};
case 'UPDATE_USERS':
const newActiveUsers = action.payload;
return {...state, activeUsers: newActiveUsers};
case 'LOGIN_ACTIVE':
return {...state, loginActive: true};
case 'LOGIN_EXIT':
return {...state, loginActive: false};
default:
return state;
}
}
export const store = createStore(messageReducer);
React Redux connect -----
const mapStateToProps = state => {
return { ...state }
}
export default connect(mapStateToProps)(Home);
This mapStateToProps returns...
{
activeUsers: []
dispatch: ƒ dispatch(action)
loginActive: true
loginDetails: {email: "", password: ""}
messages: []
__proto__: Object
}
when it should return...
{
activeUsers: []
loginActive: true
loginDetails: {email: "example#gmail.com", password:
"password"}
messages: []
__proto__: Object
}
I have tested for sure that the dispatch to the reducer is getting called, and the payload is correct. However, the reducer is failing to update the state with the LOGIN action type.
Can you try this:
const mapStateToProps = ({activeUsers,loginActive,loginDetails,messages}) => ({
activeUsers,
loginActive,
loginDetails,
messages
})

Add Todo in Redux, cannot read property Symbol(Symbol.iterator)

I'm going to add an object to the array, the second time I want to add another object the whole array becomes number one and I end up with an error, my goal is to add a task to program Todo with Redux.
I also get this errors:
TypeError: Cannot read property 'length' of undefined
TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
//todoReducer.js
import {ADD_TODO} from '../Actions/Todo';
const initialState = {
todos:[],
};
const handleAddTodo = (state, action) => {
const {todos} = state;
const newTodo =[...todos, {
id: todos.length + 1,
text: action.title,
isComplete: false,
}]
return (
todos.push(newTodo)
)
}
export default function todoRDS(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
return handleAddTodo(state, action)
default:
return state
}
}
Change your return function you return wrong value. You need to return the state
const handleAddTodo = (state, action) => {
const {todos} = state;
return {
...state,
todos: [...todos, {
id: todos.length + 1,
text: action.title,
isComplete: false,
}]
}
}
export default function todoRDS(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
return {...state, todos: [...state.todos, { id: state.todos.length +1, title: action.title, isComplete: false }] }
default:
return state
}
}
state is unmutable in react and redux you need to create a new state with old state values and add your new todo inside that new object. If you still want to use handeAddTodo try this:
const handleAddTodo = (state, action) => {
return {...state, todos: [...state.todos, { id: state.todos.length +1, title: action.title, isComplete: false }] }
}

TypeError: Cannot read property 'concat' of undefined in ReactJs

I get:
TypeError: Cannot read property 'concat' of undefined
however, I have define the 'orders' array in my initialState.
Does somebody know the reason?
import * as actionTypes from '../actions/actionTypes.js';
import { updateObject } from '../utility.js';
const initialState = {
orders: [],
loading: false,
purchased: false
};
const purchaseInit = (state, action) => {
return updateObject(state, { purchased: false });
};
const purchaseBurgerStart = (state, action) => {
return updateObject(state, { loading: true });
};
const purchaseBurgerSuccess = (state, action) => {
const newOrder = updateObject(action.orderData, { id: action.orderId });
return updateObject(state, {
loading: false,
purchased: true,
orders: state.orders.concat(newOrder)
});
};
const purchaseBurgerFail = (state, action) => {
return updateObject(state, { loading: false });
};
const fetchOrdersStart = (state, action) => {
return updateObject(state, { loading: true });
};
const fetchOrdersSuccess = (state, action) => {
return updateObject(state, {
orders: action.orders,
loading: false
});
};
const fetchOrdersFail = (state, action) => {
return updateObject(state, { loading: false });
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.PURCHASE_INIT: return purchaseInit(state, action);
case actionTypes.PURCHASE_BURGER_START: return purchaseBurgerStart(state, action);
case actionTypes.PURCHASE_BURGER_SUCCESS: return purchaseBurgerSuccess(state, action);
case actionTypes.PURCHASE_BURGER_FAIL: return purchaseBurgerFail(state, action);
case actionTypes.FETCH_ORDERS_START: return fetchOrdersStart(state, action);
case actionTypes.FETCH_ORDERS_SUCCESS: return fetchOrdersSuccess(state, action);
case actionTypes.FETCH_ORDERS_FAIL: return fetchOrdersFail(state, action);
default: return { state };
}
};
export default reducer;
Please check the state parameter this parameter does not have a state array, you can use a console.log to check what this parameter has.
I think you are missing to assign the state as initial state in the parameter.
const purchaseBurgerSuccess = (state = initialState, action)
1) This line...
case actionTypes.PURCHASE_BURGER_SUCCESS: return purchaseBurgerSuccess(state, action);
...as with all the other lines in that switch statement should be returning a new state.
So in purchaseBurgerSucess you need to make sure you're returning a new state using the state you're passing in as an argument:
const purchaseBurgerSuccess = (state, action) => {
const newOrder = updateObject(action.orderData, { id: action.orderId });
// Spread out the state you pass in as an argument
// and update those properties that have changed
return {
...state,
loading: false,
purchased: true,
orders: state.orders.concat(newOrder)
};
};
Note: your other functions fall into this trap too so those will also need to be updated.
2) Your default case in your switch statement should be:
default: return state;

Categories

Resources