reactjs - 在我的 React 应用程序中,为什么没有执行这个 Redux reducer?
问题描述
下午好,
在完成了 React 教程并阅读了所有 React 指南之后,我完成了 Redux 教程来重新编写我的工作身份验证组件以使用 Redux 而不是组件状态(我也从类切换到功能组件)。
我的 Redux 设置如下:
import { createSlice } from '@reduxjs/toolkit';
const sessionInitialState = {
authToken: null,
userLogin: null,
};
export const sessionSlice = createSlice({
name: 'session',
initialState: {
value: sessionInitialState,
},
reducers: {
sessionRegister: (state, action) => {
console.log("Storing:")
console.log(action.payload)
state.value = action.payload;
},
sessionDestroy: state => {
console.log("Destroying session")
state.value = sessionInitialState;
localStorage.removeItem("sessionData");
},
},
});
export const { sessionRegister, sessionDestroy } = sessionSlice.actions;
export const selectSession = state => state.session.value;
export default sessionSlice.reducer;
在我的登录组件中,我将身份验证令牌和用户名存储如下:
// [...]
import { useDispatch } from 'react-redux';
import { sessionRegister } from './SessionSlice';
// [...]
function LoginForm(props) {
const dispatch = useDispatch();
function onFormSubmit(event) {
// [...] This is when API response code is 200:
let sessionData = {
authToken: response.data.token,
userLogin: userName,
}
localStorage.setItem("sessionData", JSON.stringify(sessionData));
console.log("Stored:" + localStorage.getItem("sessionData"));
setApiError(null);
dispatch(sessionRegister(sessionData));
如果 Redux 中没有存储数据,我的 App 组件会显示登录表单,如果存在则显示用户名和令牌:
function App(props) {
const sessionData = useSelector(selectSession);
const storedSessionData = localStorage.getItem("sessionData");
if (storedSessionData && !sessionData.authToken) {
console.log("App init check. Storing :");
console.log(JSON.parse(storedSessionData));
sessionRegister(JSON.parse(storedSessionData));
} else {
if (!storedSessionData) console.log("No sessionData and no stored data");
}
return (
<div className="App">
<div className="topbar"><Topbar /></div>
<div className="content">
{sessionData.authToken ? (
<span>User: {sessionData.userLogin} {storedSessionData}</span>
) : (
<LoginForm />
)
}
</div>
</div>
);
}
这一切几乎都奏效了。登录组件在 API 调用之后通过 Redux 存储数据,并且也在 localStorage 中。来自 Redux 的 userLogin 由 App 显示,localStorage 内容也显示。但是,如果我刷新页面,应用程序会从 locaStorage 获取数据,但不会调用 sessionRegister(或什么也不做)。
它发生如下:
首次打开页面。控制台:No sessionData and no stored data
通过 LoginForm 登录。安慰:
Localy stored:{"authToken":"5467c25e000df49a1161c4ff8ga1f610053f62b8","userLogin":"testuser"}
Storing in Redux:
Object { authToken: "5467c25e000df49a1161c4ff8ga1f610053f62b8", userLogin: "testuser" }
现在 App 组件正确地呈现内容而不是登录表单:
User: testuser {"authToken":"5467c25e000df49a1161c4ff8ga1f610053f62b8","userLogin":"testuser"}
到目前为止,一切都很好。但是如果我刷新页面,登录表单会再次显示。在控制台中我得到:
App init check. Storing : App.js:15
Object { authToken: "5467c25e000df49a1161c4ff8ga1f610053f62b8", userLogin: "testuser" } App.js:16
App init check. Storing : App.js:15
Object { authToken: "5467c25e000df49a1161c4ff8ga1f610053f62b8", userLogin: "testuser" } App.js:16
我不明白为什么sessionRegister(JSON.parse(storedSessionData));
没有正确执行,为什么我得到两次控制台日志App init check
。
感谢您阅读所有这些内容,我们将不胜感激。
解决方案
我想你错过了一个调度
代替
sessionRegister(JSON.parse(storedSessionData));
它应该是
dispatch(sessionRegister(JSON.parse(storedSessionData)));
在您的 App 组件中。您可以通过dispatch
钩子访问
const dispatch = useDispatch()
最后但并非最不重要的一点是,您在每次渲染中都会更新存储,这就是为什么您会看到两次日志的原因。我认为您可能应该将其移至效果
const dispatch = useDispatch()
const sessionData = useSelector(selectSession);
useEffect(() => {
const storedSessionData = localStorage.getItem("sessionData");
if (storedSessionData && !sessionData.authToken) {
console.log("App init check. Storing :");
console.log(JSON.parse(storedSessionData));
sessionRegister(JSON.parse(storedSessionData));
} else {
if (!storedSessionData) console.log("No sessionData and no stored data");
}
}, [dispatch, sessionData])
推荐阅读
- ios - 如何使用滚动视图正确放大图片而不使图像飞到随机一侧
- vb.net - 将纬度/经度传递给距离函数时的类型转换问题
- prolog - 协同本体构建与Prolog
- asp.net-core - 使用 ntlm 在 Intranet 站点上进行混合身份验证,并可以更改登录用户
- python - Django Rest 返回 0 字节 zip 文件作为响应
- datetime - 将字符串转换为 xs:dateTime
- tsql - 写入具有基于它的索引和视图的表
- javascript - 调用方法时返回空数组
- java - 使用继承树模型简化数学表达式
- ios - UItableview 行未在 swift4 中与 mapkit 一起显示