【问题标题】:A given reduxer is overwritting the state set by other reducer in react native给定的减速器正在覆盖其他减速器在本机反应中设置的状态
【发布时间】:2021-06-09 22:23:26
【问题描述】:

我是反应原生(和 redux!)的新手。我正在创建一个非常简单且具有登录和仪表板屏幕的移动应用程序。

但是,我遇到了一个问题,当我调用另一个 reducer 时,它会覆盖并清除其他 reducer 先前设置的状态。

为了举例说明问题,这里是应用核心设计/代码。 登录屏幕在 Firebase 中登录用户并将操作发送到以下减速器:

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

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

到目前为止,一切顺利,现在我使用 App.js 将用户发送到仪表板,使用以下 sn-p:]

<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>

在仪表板屏幕中,我有一个按钮可以触发一个动作,该动作会转到以下减速器:

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

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

每当我单击按钮时,应用程序都会返回主屏幕。 “错误”是现在之前设置的 isLogged 变量没有未定义,导致应用返回登录。

我正在我的 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))

抱歉,问题令人困惑,但 react 似乎有太多样板文件,我无法用更少的行举例说明发生了什么。我该如何解决这个问题?

提前致谢

【问题讨论】:

  • 只有当 action.type 是特定类型时,reducer 才应该返回一个新状态。所有的 reducer 都会被调用,包括那些不应该被 reducer 处理的 action。所以你的减速器应该看起来像(state,{type,payload})=&gt;{if(type===SOME_TyPE){return {...state,modification:payload}} return state}
  • @HMR 你能进一步详细说明这个解决方案吗?

标签: javascript reactjs react-native react-redux state


【解决方案1】:

我认为您的应用程序有一些问题。首先,您的商店设置有点偏离。我认为您应该如下声明您的商店:

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

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

应该传递给 createStore 的第一个值将是您的 combineReducer。您目前仅命名为 Reducer。作为最佳实践,我保留了您的 rootReducer 参数,并简单地更改了组合减速器的名称。

但这不是您设置的唯一问题。 技术上 Redux 不会为每个调度的操作调用每个单独的 reducer(看看我为什么说 技术上 read about how combineReducers works here)。但是,出于所有意图和目的,您的组合减速器确实可以做到这一点。因此,您需要做的是设置某种系统,其中您的减速器仅在您希望更新状态时更新状态,而不是每次调度动作.

为了实现这个目标,您应该将类​​型与您的操作相关联,这将告诉您的减速器每个操作更新哪个状态切片。以你的用户减速器为例。每次分派操作时都会访问此减速器。因此,现在,当您单击您在问题中提到的仪表板按钮时,该操作不仅会转到您的 db reducer,还会转到您的 rootReducer 组合的每个 reducer。因此,您可以重构您的操作,使其看起来像这样:

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

在这个 sn-p 中,您使用您的操作声明了一个类型,我们现在可以在 reducer 中检查该类型。这将使您的减速器看起来像这样:

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
    }
}

我在这里省略了几件事,例如在 consts 文件中声明 const,并将它们导入到 action 和 reducer 中。如果您需要更多详细信息,Redux documentation 对您的工作很有帮助。

【讨论】:

  • 非常好的第一篇文章@kev_cudil!我要指出的是,您的默认返回应该是state(而不是{ ...state}),否则会触发组件不必要的重新渲染。也许值得注意的是,action reducer 应该为异步操作返回另一个函数,否则只返回 action 对象。
  • 谢谢,@buzatto!我很欣赏这些客气话。关于默认返回值的重要一点,这当然是一个疏忽。感谢您提供有用的提示!
  • 真棒@MarcosRorizJunior - 很高兴听到它!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-14
  • 2017-07-03
  • 1970-01-01
  • 2019-06-11
  • 2019-04-20
  • 1970-01-01
  • 2017-11-27
相关资源
最近更新 更多