我是反应原生(和redux!(的新手。我正在创建一个非常简单的移动应用程序,它有登录和仪表板屏幕。
然而,我遇到了一个问题,当我调用另一个reducer时,它会覆盖并清除其他reducer之前设置的状态。
举例来说,这里是应用程序的核心设计/代码。登录屏幕在Firebase中登录用户,并向以下reducer发送操作:
const initialState = {
currentUser: null,
isLogged: false
}
export const user = (state = initialState, action) => {
return {
...state,
currentUser: action.currentUser,
isLogged: action.isLogged
}
}
到目前为止,一切都很好,现在我使用App.js将用户发送到仪表板,其中包含以下片段:]
<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似乎有太多的样板,以至于我无法用更少的行来举例说明发生了什么。如何解决此问题?
提前感谢
我认为您的应用程序有一些问题。对于初学者来说,你的商店设置有点错误。我认为你应该按照以下方式声明你的商店:
const rootReducer = combineReducers({
userState: user,
dbState: db
})
const store = createStore(rootReducer, applyMiddleware(thunk))
应该传递给createStore的第一个值将是您的combinedReducer。您目前仅将其命名为Reducer。作为最佳实践,我保留了rootReducer参数,并简单地更改了组合reducer的名称。
但这并不是你设置的唯一问题从技术上Redux并没有为每个调度的操作调用每个单独的reducer(要了解为什么我说从技术上,请在此处阅读combineReducers的工作原理(。但是,无论出于何种意图和目的,您的组合减速器确实做到了这一点。因此,您需要设置某种系统,在这种系统中,只有当希望减速器更新状态时,减速器才会更新状态,而不是每次发送操作时都更新状态。
为了实现这个目标,你应该将一个类型与你的操作关联起来,它会告诉你的reducer每个操作要更新哪个状态片。以用户减速器为例。每次调度操作时都会访问此reducer。所以现在,当你点击你在问题中提到的面板按钮时,操作不仅会转到你的db reducer,还会转到你的rootReducer组合的每个reducer。因此,您可以重构您的操作,使其看起来像这样:
export const updateLoggedStatus = (isLogged) => (dispatch) => {
dispatch({
type: UPDATE_IS_LOGGED,
isLogged,
})
}
在这个片段中,您正在用您的操作声明一个类型,我们现在可以在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文件中声明consts,并将它们导入action和reducers中。如果你需要更多的细节,Redux文档对你想要做的事情非常有帮助。