How to update an object in the redux store? - reactjs

I want to add items in the object in the redux store one after the other as the user progresses in the application. Therefore, I want to add items in the store without removing the previous items in the store.
Please refer the code below:
Code for the reducer:
const currentTravelPlanDefaultState = {};
export default (state = currentTravelPlanDefaultState, action) => {
switch(action.type){
case 'ADD_PLAN':
return {
...state,
currentTravelPlan: {
...state.currentTravelPlan,
...action.currentTravelPlan
}
}
default:
return state;
}
};
Code for the action:
import uuid from 'uuid';
export const addTravelPlan = (details) => ({
type: 'ADD_PLAN',
currentTravelPlan: {
id: uuid(),
details
}
});
Code for the disptach calls:
store.dispatch(addTravelPlan({destination: 'Cuba'}));
store.dispatch(addTravelPlan({hotel: 'Cuba Grand'}));
store.dispatch(addTravelPlan({travelMode: 'AirWays'}));
However, it appears that only the last item is added in the store which is the airways and the previous items are not persisted.
Please help!
Thanks in advance.

I assume you want your data to look like this after the dispatch calls:
currentTravelPlan: {
id: uuid(),
destination: 'Cuba',
hotel: 'Cuba Grand',
travelMode: 'Airways'
}
In that case, your action code should be:
export const addTravelPlan = (details) => ({
type: 'ADD_PLAN',
currentTravelPlan: {
id: uuid(),
...details
}
});
and your reducer:
const currentTravelPlanDefaultState = {};
export default (state = currentTravelPlanDefaultState, action) => {
switch(action.type){
case 'ADD_PLAN':
return {
...state,
...action.currentTravelPlan
}
default:
return state;
}
};

In reducer you should set currentTravelPlan to empty object so you know how your state going to look.
const currentTravelPlanDefaultState = {
currentTravelPlan: {}
};
export default (state = currentTravelPlanDefaultState, action) => {
switch(action.type){
case 'ADD_PLAN':
return {
...state,
currentTravelPlan: {
...state.currentTravelPlan,
...action.currentTravelPlan
}
}
default:
return state;
}
};
in your action you are passing data wrongly. you need to destructure details before sending it. if you don't destructure it will always pass details: your object
import uuid from 'uuid';
export const addTravelPlan = (details) => ({
type: 'ADD_PLAN',
currentTravelPlan: {
id: uuid(),
...details
}
});

Related

store updated value in redux

i got two values i.e.company and id from navigation.
let id = props.route.params.oved.toString();
console.log("id-->",id);
let company = props.route.params.company.toString();
console.log("company--->",company);
i got two values as a integer like this:--
id-->1
comapny-->465
enter image description here
Description of the image:---
if i am giving input 1 in that textInput and click on the card(lets say first card i.e.465 then i am getting those two values in navigation as in interger that i have mention above.so each time i am getting updated values.
i am getting updated values from navigation.
so i want to store those values in redux.
action.js:--
import { CHANGE_SELECTED_COMPANY } from "./action-constants";
export const changeCompany = (updatedCompany, updatedId) => {
return {
type: CHANGE_SELECTED_COMPANY,
updatedCompany,
updatedId,
};
};
reducer.js:--
import { CHANGE_SELECTED_COMPANY } from "../actions/action-constants";
const initialState = {
company: "",
id: "",
};
const changeCompanyReducer = (state = initialState, action) => {
switch (action.type) {
case CHANGE_SELECTED_COMPANY:
return {
company: {
company: action.updatedCompany,
id: action.updatedId,
},
};
}
return state;
};
export default changeCompanyReducer;
congigure-store.js:--
import changeCompanyReducer from "./reducers/change-company-reducer";
const rootReducer = combineReducers({changeCompanyReducer});
How can i store the update values getting from navigation in Redux?
could you please write code for redux??
First I would recommend writing your action like this:
import { CHANGE_SELECTED_COMPANY } from "./action-constants";
export const changeCompany = (payload) => {
return {
type: CHANGE_SELECTED_COMPANY,
payload // inside payload you can pass: { updatedCompany: '...', updatedId: '...' }
};
};
And then you need to change your reducer from what you wrote to this:
import { CHANGE_SELECTED_COMPANY } from "../actions/action-constants";
const initialState = {
company: "",
id: "",
};
const changeCompanyReducer = (state = initialState, action) => {
switch (action.type) {
case CHANGE_SELECTED_COMPANY:
const { updatedCompany, updatedId } = action.payload;
// notice the changes I made in the return statment.
return {
...state,
company: updatedCompany,
id: updatedId
};
// you can return the state here
default:
return state;
}
};
export default changeCompanyReducer;

React Redux how to add data to object's array

My user structure is:
user = {
email: 'email',
flashcards: []
}
And i would like to add data into user's flashcards array (using redux)
My user-reducer
import { UserActionTypes } from './user.types';
const INITIAL_STATE = {
currentUser: null,
};
// GETS STATES OBJ AND RECIVES AN ACTION
const userReducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case UserActionTypes.SET_CURRENT_USER:
return {
...state,
currentUser: action.payload,
};
case UserActionTypes.ADD_FLASHCARD:
return {
...state,
currentUser: action.payload,
};
default:
return state;
}
};
export default userReducer;
user-actions
export const addFlashCard = user => ({
type: UserActionTypes.ADD_FLASHCARD,
payload: user.flashcards,
});
And when i'm doing so my payload is undefined.
Could you give me some hints?
You are currently overwriting currentUser with the value of user.flashcards from the redux action. To add new flashcards, the ADD_FLASHCARD branch of your reducer should look more like this:
case UserActionTypes.ADD_FLASHCARD:
return {
...state,
currentUser: {
...state.currentUser,
flashcards: [
...state.currentUser.flashcards,
...action.payload
]
}
};

react-redux store data - reducer setter

I'm trying to store a dictionary in react-redux in react-native.
So my action looks like this :
let data = {};
export const setData = (pData) => ({
type: 'SET',
data: pData,//I don't know how to store the data in data declared in parent
});
export const getData = () => ({
type: 'GET',
data: data,
});
And my reducer looks like this :
const items = (state = [], action) => {
switch (action.type) {
case 'SET':
return [
//I don't know how to set the data here
];
case 'GET':
return state;
default:
return null;
}
};
export default items;
I looked in many tutorial on YouTube, they just you need to paste this, and boom.
If I get cleared with one dictionary, I think I can work with others.
This part almost right. You don't need "GET" to get data and this part let data = {} should be in reducer;
export const setData = (pData) => ({
type: 'SET',
data: pData,
});
/*
export const getData = () => ({
type: 'GET',
data: data,
});
*/
Reducer
const initState = {
data:[],
anotherSate:[]
}
const rootReducer = (state = initState, action) => {
switch(action.type){
case 'SET': {
return {
...state, // if you have more states
data: [action.data, ...state.data]
}
}
default:
return state;
}
}
export default rootReducer;
You can get your "Data". "New" component
//Your component code
//...
this.props.data // here is your "data"
//...
const mapStateToProps = (state) => {
return {
data: state.data,
}
}
export default connect(mapStateToProps)(NewComponent);
In order to check if your Reducer works, try to add something in your initState and extract the data in NewComponent
const items = (state = [], action) => {
switch (action.type) {
case 'SET':
return {
...state, // adding the previous state first
data: action.data // here data can be any keyword you want to save your dictionary in
}
case 'GET':
return state;
default:
return null;
}
};

Modifying state from another reducer in react

I'm pretty new in react so this might be a silly question.
I'm working on an app that manage rss feeds, so the structure of my entire app is similar to this one
<div className="App">
<Header />
<Feeds />
</div>
both components have their own reducer and actions.
the problem appears when I'm trying to create a new feed (actually managed in the feeds reducer) from my header component. so I have to access to the state of the feedsReducer from my headerReducer.
I'm not sure how to proceed at this point.
should I access the feeds reducer from the header component? ( this also implies that the feedsReducer needs to know my header actions)
I'll add some code to make the problem clear
index.js
import feedsReducer from './components/Feeds/FeedsReducer';
import headerReducer from './components/Header/HeaderReducer';
const rootReducer = {
feeds:feedsReducer,
header: headerReducer
};
const store = createStore(combineReducers(rootReducer));
Header/Header.js
import { ADD_FEED } from './actions';
class Header extends Component {
state = {
feedUrl: ""
};
addFeed = () => {
axios.post(
'/feeds/add',
{
url: 'myNewRssFeed.com'
})
.then(feed => {
//this is calling the HeaderReducer
this.props.addFeed(feed.data);
})
.catch(err => console.log(err));
}
}
const mapDispatchToProps = dispatch => {
return {
addFeed: (feed) => dispatch({ type: ADD_FEED, payload: { feed } })
};
};
export default connect(null, mapDispatchToProps)(Header);
Header/actions.js
export const ADD_FEED = "ADD_FEED";
HeaderComponent/HeaderReducer.js
const reducer = (state, action) => {
const newState = {
...state
}
switch (action.type) {
case storeActions.ADD_FEED:
// at this point newState.feeds doesn't exist because it's part from the FeedsReducer
newState.feeds = newState.feeds.push(action.payload.feed);
break;
}
return newState;
}
Feeds/FeedsReducer.js
const initialState = {
feeds: []
}
const reducer = (state = initialState, action) => {
const newState = {
...state
}
switch (action.type) {
//this action is commented because was recently moved to the headerComponent/actions.js
/* case storeActions.ADD_FEED:
newState.feeds = newState.feeds.push(action.payload.feed);
break; */
case storeActions.LOAD_FEEDS:
newState.feeds = action.payload.feeds;
break;
}
return newState;
}
Thanks in advice.
I don't really think you need to access reducer in any way. Reducer function will update store based on action it's listenning to.
Here is an example:
import * as constants from 'constantpathhere';
export function feedReducer(state = INITIAL_STATE, action) {
const { type, payload } = action;
switch(type) {
case constants.ADD_FEED: // listen to ADD_FEED action
return {... state, data: payload };
case constants.LOAD_FEEDS: // listen to LOAD_FEEDS
return {...state, loading: true }
...
default:
return state;
}
}
export function headReducer(state = INITIAL_STATE, action) {
const { type, payload } = action;
switch(type) {
case constants.ANY_ACTION: // listen to ADD_FEED action
return {... state, data: payload };
case constants.ANY_OTHER_ACTION_LOADING: // listen to LOAD_FEEDS
return {...state, loading: true }
...
default:
return state;
}
}
//ACTIONS
export function loadFeeds() {
return {
type: constants.LOAD_FEEDS
}
}
export function addFeed(payload) {
return {
type: constants.ADD_FEED,
payload
}
}
export function triggerAnyAction(payload) {
return {
type: constants.ANY_ACTION,
payload
}
}
These actions above may be dispatched from any component, be it Header or Feeds, only reducer(s) listening to that particular action will update the store.
Briefly, you only need to know which action to dispatch where and only reducer listing to that action will do whatever you instructed it to do

ReactJS modifiying data in state

I just starting on React, and starting to do a todo list. It has functionalities like add, modify(done/pending) and remove task.
Below is my action
export const ADD_TASK = 'ADD_TASK';
export const TOGGLE_TASK = 'TOGGLE_TASK';
export const REMOVE_TASK = 'REMOVE_TASK';
export const FILTER_TASK = 'FILTER_TASK';
let todoId = 1;
export function addTask(task) {
let todo = {
id: todoId++,
name: task,
status: 0,
visible: true
};
return {
type: ADD_TASK,
payload: todo
};
}
export function toggleTask(id) {
return {
type: TOGGLE_TASK,
payload: id
};
}
export function removeTask(id) {
return {
type: REMOVE_TASK,
payload: id
};
}
export function filterTask(id) {
return {
type: FILTER_TASK,
payload: id
};
}
and my reducer :
import { ADD_TASK, TOGGLE_TASK, REMOVE_TASK, FILTER_TASK } from '../actions/index';
let filterStatus = -1;
//initial state is array because we want list of city weather data
export default function(state = [], action) {
// console.log('Action received', action);
const toggling = function (t, action) {
if(t.id !== action)
return t;
return Object.assign({}, t, {
status: !t.status
})
};
const visibility = function(t, action) {
return Object.assign({}, t, {
visible: action === -1 ? true : t.status == action
})
};
switch(action.type) {
case ADD_TASK :
//return state.concat([ action.payload.data ]); //in redux reducer dont modify the state, instead create a new one baesd on old one. Here concat is create a new of old one and add a new data
return [ action.payload, ...state];
case TOGGLE_TASK :
return state.map(s => toggling(s, action.payload)).map(t => visibility(t, filterStatus));
case REMOVE_TASK :
return state.filter(s => { return (s.id != action.payload) } );
case FILTER_TASK :
filterStatus = action.payload;
return state.map(t => visibility(t, action.payload));
}
return state;
}
I read somewhere that modifying state is reducer is a bad practice, yet I feel that I'm doing it in my reducer.
Could anyone suggest the correct way of handling add,remove, update value state in the reducer ?
Thank you
i think you need two reducers: one for managing visibility stuff, one for adding, toggling and removing tasks.
so for the second part i would like do this.
export const ADD_TASK = 'ADD_TASK';
export const TOGGLE_TASK = 'TOGGLE_TASK';
export const REMOVE_TASK = 'REMOVE_TASK';
let todoId = 1;
export addTask = (text) => ({
type: ADD_TASK,
id: todoId++,
text
});
export toggleTask = (id) => ({
type: TOGGLE_TASK,
id
});
export removeTask = (id) => ({
type: REMOVE_TASK,
id
});
export function todosReducer(state = [], action) {
switch(action.type) {
case ADD_TASK :
return [...state, {id: action.id, text: action.text, completed: false}];
case TOGGLE_TASK :
return state.map(task => task.id !== action.id ? task : {...task, completed: !task.completed});
case REMOVE_TASK :
return state.filter(task => task.id !== action.id);
}
return state;
}

Resources