下午好,
在做了React教程,并阅读了所有React指南之后,我做了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中没有存储数据,我的应用程序组件将显示登录表单;如果Redux中存在用户名和令牌,则显示用户名和令牌:
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>
);
}
这一切几乎都奏效了。login组件在API调用后通过Redux存储数据,也存储在localStorage中。应用程序会显示Redux的用户登录名,也会显示localStorage内容。但如果我刷新页面,应用程序将从locaStorage获取数据,但不会调用sessionRegister(或不执行任何操作)。
情况如下:
翻开书页。控制台:无会话数据和无存储数据
通过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)));
在应用程序组件中。您可以使用钩子访问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])