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;
Related
I am making this shopping cart in redux-toolkit and rtk query. I want to change the cartItem index with product id.
I think the problem is with this line of code:
const cartItems = state.cartItems
My full code:
import { createSlice, current } from '#reduxjs/toolkit';
const initialState = {
cartItems: [],
};
export const cartSlice = createSlice({
name: 'cartSlice',
initialState: initialState,
reducers: {
setToCart: (state, action) => {
const { payload:product, newQty = 1 } = action;
const cartItems = state.cartItems;
const quantity = cartItems?.[product?._id]
? parseInt(cartItems[product._id].quantity + newQty)
: 1;
cartItems[product._id] = {
...product,
quantity,
};
return {
...state,
cartItems: cartItems
}
},
},
});
export const {setToCart} = cartSlice.actions;
export default cartSlice.reducer;
Here is action.payload:
{
img: "_OCT2HGtyHbioAuVTMGcA-mauntain.jpg",
name: "iphone",
price: 600001,
_id: "60d375ed3224711bc0f3538a"*
}
As the error states, when using an Immer-powered reducer you must Either return a new value or modify the draft.
You are modifying the cartItems array. You do not need to return anything from your reducer. Just modify the values that you want to change. That's the magic of Redux Toolkit! (powered by Immer).
There are some other issues with your reducer:
action will not have a property newQty. It will only have a type and payload. Perhaps newQty is a property of the payload?
It seems like cartItems is a dictionary keyed by _id, but you initialize it as an empty array [] instead of an empty object {}.
parseInt doesn't make sense outside of an addition statement. parseInt("2" + "2") will be 22, not 4.
A "fixed" version might look like this, depending on how you structure your payload:
import { createSlice } from '#reduxjs/toolkit';
const initialState = {
cartItems: {},
};
export const cartSlice = createSlice({
name: 'cartSlice',
initialState: initialState,
reducers: {
setToCart: (state, action) => {
const { payload } = action;
const { product, newQty = 1 } = payload;
const cartItems = state.cartItems;
// If already in cart, increase quantity.
if (cartItems[product._id]) {
cartItems[product._id].quantity += newQty;
}
// Otherwise add to cart.
else {
cartItems[product._id] = {
...product,
quantity: newQty
}
}
// Don't return anything.
},
},
});
export const {setToCart} = cartSlice.actions;
export default cartSlice.reducer;
I am trying to add redux to Next.js. It is not working Ok
This is my reducerSlice file
import { createSlice } from '#reduxjs/toolkit';
import { HYDRATE } from 'next-redux-wrapper';
import { AppState } from '..';
export const ProfileSlice = createSlice({
name: 'profile',
initialState: {
name: [] as any
},
reducers: {
setProfileData: (state, action) => {
state.name = [...state.name, action.payload];
}
},
extraReducers: {
[HYDRATE]: (state, action) => {
if (!action.payload.profile.name) {
return state;
}
const nextState = {
...state, // use previous state
name: [...state.name, ...action.payload.profile.name]
};
return nextState;
}
}
});
export const { setProfileData } = ProfileSlice.actions;
export const selectProfile = (state:AppState)=>state.profile;
export default ProfileSlice.reducer;
When I use server side rendering to dispatch data to the store a single value is stored okay but when i use array the hydration is called multiple times
You can see in this image Emma is logged 4 times
I don't know what to do
Here is how I used SSR in profile file
export const getServerSideProps = wrapper.getServerSideProps(store => async ({ query }) => {
console.log('store state on the server before dispatch', store.getState());
const response = await fetch(
`https://reqres.in/api/users/${Math.floor(Math.random() * 10 + 1)}`
);
const { data } = await response.json();
const data2 = data.first_name;
store.dispatch(setProfileData(`${data.first_name}`));
return {
props: {
data2
}
};
});
I just ran into an issue, with my redux store not updating after a matched action is dispatched.
I managed to get my reducer to work, here it is:
// working approach
import { AnyAction } from 'redux';
export interface IReducerState {
config: (Record<string, any> & {
name: string;
age: string;
}) | null
}
const initialState = {
config: null,
};
const reducer = (state: IReducerState = initialState, action: AnyAction): IReducerState => {
const { type, payload } = action;
switch (type) {
case 'MATCHED_ACTION':
return {
...state,
config: {
...state.config,
name: payload.clear ? '' : state.config.name,
age: payload.clear ? '' : state.config.age,
[payload.field]: payload.value,
},
};
default:
return { ...state };
}
};
export default reducer;
But before, however, I was doing the following:
// alternative approach
case 'MATCHED_ACTION':
const result = { ...state.config };
if (payload.clear) {
result.name = '';
result.age = '';
}
if (payload.field && payload.value) {
result[payload.field] = payload.value;
}
return {
...state,
config: result
};
What am I doing wrong? Why is the alternative approach incorrect?
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
}
});
Example redux tree with contact Adam in the Friends group:
{
groups: {
1: {
name: "Friends"
contacts: [1]
}
}
contacts: {
1: {
name: "Adam"
}
}
}
Now I would like to create a new contact in the Friends group and the result would be something like:
{
groups: {
1: {
name: "Friends"
contacts: [1, 2]
}
}
contacts: {
1: {
name: "Adam"
},
2: {
name: "Bethany"
}
}
}
Currently I am creating the new contact id before I run the redux action on both reducers. However this feels really messy, is there a better way to go about doing this? My current code is below:
contact.js
import { connect } from 'react-redux';
function Contact({ createContact, groupId, newContactId }) {
function onContactCreate(name) {
createContact(newContactId, groupId, name);
}
// ...
}
const mapStateToProps = (state) => {
return {
newContactId: state.get('contacts').size + 1
};
};
export function mapDispatchToProps(dispatch) {
return {
createContact: (newContactId, groupId, name) => dispatch({
type: 'CREATE_CONTACT',
newContactId,
groupId,
name
})
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Contact);
contact-reducer.js
import { fromJS } from 'immutable';
const initialState = fromJS({});
function contactReducer(state = initialState, action) {
switch (action.type) {
case 'CREATE_CONTACT': {
return state
.set(action.id, fromJS({
name: action.name
}));
}
default:
return state;
}
}
export default contactReducer;
group-reducer.js
import { fromJS } from 'immutable';
const initialState = fromJS({});
function groupReducer(state = initialState, action) {
switch (action.type) {
case 'CREATE_CONTACT': {
let id = action.groupId;
return state
.updateIn([id, 'contacts'], (contacts) => contacts.push(action.id));
}
default:
return state;
}
}
export default groupReducer;
You do indeed have to create the ID before you dispatch the action. The ID shouldn't depend on the current state. If you use time travel or Redux Dev tools to edit history, the same action could create an item with a different ID. This would lead subsequent actions to use the incorrect ID.
In general, the identity of an object should be bound to the object and not created separately.