Updating a reducer from another reducer in react-native - react-native

I want to update the state of one reducer from another reducer in react-native.My code is like this.
This is the action.
export const doLike = payload => {
// Recieving response from the server
let updatedPost = {
Id: 1,
userId: 1,
postId: payload.post._id,
__v: 1,
count: payload.type === 1 ? 10 : 1
};
return {
type: SM_ACTION_LIKE,
post: updatedPost
};
};
This is the smReducer which accepts the action.
const initialState = {
post: {}
};
const smReducer = (state = initialState, action) => {
switch (action.type) {
case SM_ACTION_LIKE:
return {
...state,
post: action.post
};
break;
default:
return state;
}
return state;
};
export default smReducer;
Now I want to change the posts array of mainFeedReducer from here. My mainFeedReducer is this. I want to access the posts array of mainFeedReducer from smReducer.
const initialState = Immutable({
posts: [],
featuredWorkouts: []
});
const mainfeedReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_MAIN_FEED:
return {
...state,
posts: action.mainFeedData.posts,
featuredWorkouts: action.mainFeedData.featuredWorkouts
};
break;
default:
return state;
}
};
How can I achieve this?

Redux architecture revolves around a strict unidirectional data flow.
The correct way would be to design your reducers in such a way that they handle more data.
As mentioned in the docs
If a reducer needs to know data from another slice of state, the state tree shape may need to be reorganized so that a single reducer is handling more of the data.
Alternatives
You may consider using redux-thunk, since the inner
function, that recieves two parameters return (dispatch, getState),
has an access to the entire state map.
If you have an instance of your store object, then you can directly access at the states by doing store.getState()

Related

Reducer gives an invalid attempt spread non-iterable instance

Would like to know whats wrong with my code it gives an error when i try dispatching a action using redux this is my reducer.js code
import {UPDATE_LOGIN} from './constants'
const initialState = {
isLogged:false
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case UPDATE_LOGIN:
return [
...state,
{
isLogged:action.isLogged
}
];
default:
return state;
}
}
export default reducer;
it gives a Invalid attempt to spread non-iterable instance.
In order to be iterable, non-array objects must have a Symbol.iterator method.
Your state is an object, and you try to destructure it as an array. In addition, you try to include the object, instead of changing the property. Try this:
const reducer = (state = initialState, action) => {
switch (action.type) {
case UPDATE_LOGIN:
return {
...state,
isLogged: action.isLogged
};
default:
return state;
}
}

useSelector causes multiple re-renders

When using react-devtools it tells me that the reason my root component re-renderd was because hooks changed?
when I remove any useSelectors, my root component renders only once, when enabled it renders 6 times.
what are some guesses as to why this is happening?
import {
/// Data State Constants...
SET_USER_DATA,
SET_BADGE_COUNT,
} from "../Actions/gameState";
const initialState = {
/// Data state...
userData: [],
badgeCount: 0,
};
export default function gameState(state = initialState, action) {
const { type, payload } = action || {};
switch (type) {
/////////////////////////
/// Data state Reducers...
/////////////////////////
case SET_USER_DATA: {
return { ...state, userData: payload };
}
case SET_BADGE_COUNT: {
return { ...state, badgeCount: payload };
}
default:
return state;
}
}
Ok, the thing is: the useSelector compare the new value with the old one with a strict ===. You can either call one useSelector per field or implement the shallowEqual from react-redux:
const someState = useSelector(state=>state.myState.someState, shallowEqual)
Here the documentation:
https://react-redux.js.org/next/api/hooks#equality-comparisons-and-updates

What does wrapping a variable in {} mean in a reducer function REACT NATIVE?

I am new to React native and I came across code for a reducer function but I am confused on why "token" is wrapped in brackets. Does it make token into a dynamic thing or something?
Can someone please explain why it is so? Thank you so much!
/** The reducer is in charge of updating the app state based on the dispatched action. **/
//Action Types
export const CREDENTIALED = 'auth/CREDENTIALED';
export const RESET_DATA = 'auth/RESET_DATA';
export const initialState = {
isLoading: true,
token: null,
};
//REDUCER
const authReducer = (state = initialState, action) => {
switch (action.type) {
case CREDENTIALED: {
let {token} = action;
return {...state, isLoading: true, token};
}
case RESET_DATA: {
return {...state, ...initialState};
}
default:
return state;
}
};
export default authReducer;
Not a react native expert by any stretch of the imagination, but it looks like token is just being destructured from action. Roughly the same as:
const dict = {
"alpha": 'a',
"beta": 'b',
}
const {alpha} = dict
console.log(alpha) // you should expect "a" to be printed out

Duplicate items on redux state tree

I am trying to update my Redux state with a toggle button. My LB reducer is comprised of 2 reducers, an array called listItems for displaying a unique number of values, and filterBarState which is used as a reference to the current filters.
While my initial state is correct, my reducer places the toggle action outside of filterBarState
Below is my LB object reducer
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case EVENT_FILTER_PRESSED:
return {
// Reducer composition
filterBarState: eventFilter(state.filterBarState, action),
listItems: eventItems(state.listItems, action)
};
case MALE_FILTER_PRESSED:
// console.log('isMaleFilterOn:', action.isMaleFilterOn)
return { ...state, isMaleFilterOn: action.isMaleFilterOn };
case FEMALE_FILTER_PRESSED:
// console.log('isFemaleFilterOn:', action.isFemaleFilterOn)
return { ...state, isFemaleFilterOn: action.isFemaleFilterOn };
In my React Native Container Component, I have attempted some (suspect) ES6 destructuring in mapStateToProps which, if I don't include, the entire filterBarState returns undefined
const mapStateToProps = ({ LB }) => {
const { filterBarState: { isMaleFilterOn, isFemaleFilterOn, currentSelectedEvent, currentSelectedRow }, listItems, isCurrentlySelected } = LB;
return { isMaleFilterOn, isFemaleFilterOn, currentSelectedEvent, currentSelectedRow, listItems, isCurrentlySelected };
Any tips / suggestions on a fix would be greatly appreciated!
Based on the EVENT_FILTER_PRESSED handler, it looks like you are not updating the isMaleFilterOn and isFemaleFilterOn at the correct level. Try this:
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case EVENT_FILTER_PRESSED:
return {
// Reducer composition
filterBarState: eventFilter(state.filterBarState, action),
listItems: eventItems(state.listItems, action)
};
case MALE_FILTER_PRESSED:
// console.log('isMaleFilterOn:', action.isMaleFilterOn)
return { ...state, filterBarState: { ...state.filterBarState, isMaleFilterOn: action.isMaleFilterOn } };
case FEMALE_FILTER_PRESSED:
// console.log('isFemaleFilterOn:', action.isFemaleFilterOn)
return { ...state, filterBarState: { ...state.filterBarState, isFemaleFilterOn: action.isFemaleFilterOn } };
}

How do I add an element to array in reducer of React native redux?

How do I add elements in my array arr[] of redux state in reducer?
I am doing this-
import {ADD_ITEM} from '../Actions/UserActions'
const initialUserState = {
arr:[]
}
export default function userState(state = initialUserState, action)
{
console.log(arr);
switch (action.type)
{
case ADD_ITEM:
return {
...state,
arr: state.arr.push([action.newItem])
}
default:
return state
}
}
Two different options to add item to an array without mutation
case ADD_ITEM :
return {
...state,
arr: [...state.arr, action.newItem]
}
OR
case ADD_ITEM :
return {
...state,
arr: state.arr.concat(action.newItem)
}
push does not return the array, but the length of it (docs), so what you are doing is replacing the array with its length, losing the only reference to it that you had. Try this:
import {ADD_ITEM} from '../Actions/UserActions'
const initialUserState = {
arr:[]
}
export default function userState(state = initialUserState, action){
console.log(arr);
switch (action.type){
case ADD_ITEM :
return {
...state,
arr:[...state.arr, action.newItem]
}
default:return state
}
}
If you need to insert into a specific position in the array, you can do this:
case ADD_ITEM :
return {
...state,
arr: [
...state.arr.slice(0, action.pos),
action.newItem,
...state.arr.slice(action.pos),
],
}
Since this question gets a lot of exposure:
If you are looking for the answer to this question, there is a good chance that you are following a very outdated Redux tutorial.
The official recommendation (since 2019) is to use the official Redux Toolkit to write modern Redux code.
Among other things, that will eliminate string action constants and generate action creators for you.
It will also employ methods that allow you to just write mutating logic in your Reducers created by createReducer or createSlice, so there is no need to write immutable code in Reducers in modern Redux in the first place.
Please follow the official Redux tutorials instead of third-party tutorials to always get the most up-to-date information on good Redux practices and will also show you how to use Redux Toolkit in different common scenarios.
For comparison, in modern Redux this would look like
const userSlice = createSlice({
name: "user",
initialState: {
arr:[]
},
reducers: {
// no ACTION_TYPES, this will internally create a type "user/addItem" that you will never use by hand. You will only see it in the devTools
addItem(state, action) {
// you can use mutable logic in createSlice reducers
state.arr.push(action.payload)
}
}
})
// autogenerated action creators
export const { addItem } = slice.actions;
// and export the final reducer
export default slice.reducer;
If you want to combine two arrays, one after another then you can use
//initial state
const initialState = {
array: [],
}
...
case ADD_ARRAY :
return {
...state,
array: [...state.array, ...action.newArr],
}
//if array = [1,2,3,4]
//and newArr = [5,6,7]
//then updated array will be -> [1,2,3,4,5,6,7]
...
This Spread operator (...) iterates array element and store inside the array [ ] or spreading element in the array, what you can simply do using "for loop" or with any other loop.
I have a sample
import * as types from '../../helpers/ActionTypes';
var initialState = {
changedValues: {}
};
const quickEdit = (state = initialState, action) => {
switch (action.type) {
case types.PRODUCT_QUICKEDIT:
{
const item = action.item;
const changedValues = {
...state.changedValues,
[item.id]: item,
};
return {
...state,
loading: true,
changedValues: changedValues,
};
}
default:
{
return state;
}
}
};
export default quickEdit;
The easiest solution to nested arrays is concat():
case ADD_ITEM:
state.array = state.array.concat(action.paylod)
return state
concat() spits out an updated array without mutating the state. Simply set the array to the output of concat() and return the state.
This worked for me
//Form side
const handleSubmit = (e) => {
e.preventDefault();
let Userdata = { ...userdata, id: uuidv4() };
dispatch(setData(Userdata));
};
//Reducer side
const initialState = {
data: [],
};
export const dataReducer = (state = initialState, action) => {
switch (action.type) {
case ActionTypes.SET_DATA:
return { ...state, data: [...state.data, action.payload] };
default:
return state;
}
};