简体   繁体   中英

A given reduxer is overwritting the state set by other reducer in react native

I'm new to react native (and redux.). I'm creating a mobile app that is very simple and has a login and dashboard screens.

However, I'm having a problem where when I call another reducer it overwrites and cleans the state previously set by other reducer.

To exemplify the problem, here is the app core design/code. The Login Screen logins the user in Firebase and sends an actions to the following reducer:

const initialState = {
    currentUser: null,
    isLogged: false
}

export const user = (state = initialState, action) => {
    return {
        ...state,
        currentUser: action.currentUser,
        isLogged: action.isLogged
    }
}

So far, so good, now I use the App.js to send the user to the dashboard, with the following snippet:]

<NavigationContainer>
      {
        isLogged ? (
          <Stack.Navigator initialRouteName="DashboardScreen">
            <Stack.Screen name="DashboardScreen" component={DashboardScreen} options={{ headerShown: false }} />
          </Stack.Navigator>
        ) : (
            <Stack.Navigator initialRouteName="LoginScreen">
              <Stack.Screen name="LoginScreen" component={LoginScreen} options={{ headerShown: false }} />
            </Stack.Navigator>
          )
      }
    </NavigationContainer>

In the dashboard screen I have a button that trigger an action that goes to the following reducer:

const initialState = {
    lastUpdate: null,
    isSync: false
}

export const db = (state = initialState, action) => {
    return {
        ...state,
        lastUpdate: action.lastUpdate,
        isSync: action.isSync
    }
}

Whenever I click the button the app goes back to the main screen. The 'error' is that now the isLogged variable, which was set previously, is not undefined causing the app to go back to login.

I'm creating the reducers using the following code in my App.js:

import { combineReducers  } from "redux";
import { user } from "./user";
import { db } from "./db";

const Reducers = combineReducers({
    userState: user,
    dbState: db
})

const store = createStore(rootReducer, applyMiddleware(thunk))

Sorry for the problem being confused, but react seems to have so many boilerplate that I was unable to exemplify what was happening with fewer lines. How can I fix this issue?

Thanks in advance

I think that there are a few things goin on with your app here. For starters, your store setup is a bit off. I believe that you should declare your store as follows:

const rootReducer = combineReducers({
    userState: user,
    dbState: db
})

const store = createStore(rootReducer, applyMiddleware(thunk))

The first value that should be passed to createStore will be your combinedReducer. Which you are currently naming just Reducer. As a best practice I kept your rootReducer parameter, and simply changed the name of your combined reducer.

But this isn't the only problem with your setup. Technically Redux does not call every individual reducer for every dispatched action (to see why I say technically read about how combineReducers works here ). But your combined reducer does, for all intents and purposes, do exactly that. So what you need to do is setup some sort of system wherein your reducers are only updating state when you want them to update state, and not every time that an action is dispatched.

To achieve this goal, you should associate a type to your action, which will tell your reducer which slice of state to update with each action. Take your user reducer, for example. This reducer will be accessed every time that an action is dispatched. So now, when you click on the dashboard button that you mention in your question, the action doesn't only go to your db reducer, but it goes to every reducer that is combined by your rootReducer. So you can refactor your actions to look something like this:

export const updateLoggedStatus = (isLogged) => (dispatch) => {
  dispatch({
    type: UPDATE_IS_LOGGED,
    isLogged,
  })
}

In this snippet you are declaring a type with your action that we can now check for in the reducer. This would allow your reducer to look something like this:

const initialState = {
    currentUser: null,
    isLogged: false
}

export const user = (state = initialState, action) => {

    switch(action.type) {
        case: SET_CURRENT_USER:
            return {
                ...state,
                currentUser: action.currentUser
            }
        case: UPDATE_IS_LOGGED:
            return {
                  ...state,
                  isLogged: action.isLogged
            }
        default:
            return state
    }
}

I am leaving out a couple of things here,such as declaring consts in a consts file, and importing them into both actions and reducers, for example. If you need further details, the Redux documentation can be very helpful for what you are looking to do.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM