Par*_*ker 2 reactjs react-router react-context react-hooks use-effect
菜鸟在这里反应一下。
我正在尝试使用 Context、useState、useEffect 和 sessionStorage 的组合来构建一个在页面刷新时持续运行的功能全局数据存储。
当用户登录应用程序时,我会获取 API,然后setUserData当我收到响应时。
这部分效果很好,但我意识到,如果用户“刷新”他们的页面,应用程序会将userDataconst 重置为null(并且页面因此崩溃)。
我研究了一些关于使用 useEffect 和 sessionStorage 的组合来有效替换userDatasessionStorage 中当前内容的文章和视频,这似乎是处理页面刷新的明智方法。[来源: React Persist State to LocalStorage with useEffect by Ben Awad]
但是,我似乎无法让 useEffect 发挥作用。由于某种原因 useEffect 只在/路线上触发而不是在/dashboard路线上?
我希望因为 useEffect 位于 App.js 中,所以每次刷新任何路由时它都会运行(从而从 sessionStorage 检索最新数据)。
我在 App.js 中添加了一些控制台日志记录,以了解何时触发事件,并在下面包含这些日志。
我对 useEffect 的理解不正确吗?为什么它只在刷新路由时触发,而不是在刷新/页面时触发?/dashboard
import { useState, createContext, useEffect } from 'react'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import '../css/app.css';
import Login from './auth/login';
import Dashboard from './dashboard/dashboard';
export const AppContext = createContext(null);
function App() {
console.log("App Load")
const [userData, setUserData] = useState(null);
useEffect(() => {
console.log("Use effect ran");
const user = sessionStorage.getItem("user");
if (user) {
setUserData(JSON.parse(user));
console.log("Retreived session storage");
}
},[]);
return (
<AppContext.Provider value={ { userData, setUserData } }>
<BrowserRouter>
<div className="App">
<Routes>
<Route path="/" element={<Login />}></Route>
<Route path="/dashboard" element={<Dashboard />}></Route>
</Routes>
</div>
</BrowserRouter>
</AppContext.Provider>
);
}
export default App;
Run Code Online (Sandbox Code Playgroud)
import { useContext } from 'react'
import '../../css/app.css'
import { AppContext } from '../app';
import Nav from '../../components/primary-nav';
const Dashboard = () => {
const { userData } = useContext(AppContext);
return (
<div>
<Nav />
<div id='dashboard'>
<div id='title' className='mt-[38px] ml-[11%]'>
<div className='h2'>Good morning, { userData.user_info.first_name }!</div>
</div>
</div>
</div>
)
}
export default Dashboard;
Run Code Online (Sandbox Code Playgroud)
我希望刷新仪表板页面时 useEffect() 会触发,但这里分别是日志。
您能帮我理解为什么 App Load 被多次触发(似乎触发了 4 次吗?)
该useEffect钩子具有空的依赖数组,仅运行一次,并且由于它位于路由器之外,因此与任何路由完全无关。此外,该useEffect钩子在初始渲染结束时运行,因此在初始渲染周期中使用了错误的初始状态值。
直接从 sessionStorage 初始化状态,并使用useEffect钩子在本地状态发生变化时保留它。
例子:
function App() {
console.log("App Load")
const [userData, setUserData] = useState(() => {
const user = sessionStorage.getItem("user");
return JSON.parse(user) || null;
});
useEffect(() => {
console.log("userData updated, persist state");
sessionStorage.getItem("user", JSON.stringify(userData));
}, [userData]);
return (
...
);
}
Run Code Online (Sandbox Code Playgroud)
与任何潜在的空/未定义值一样,消费者在访问此状态时必须使用空检查/保护子句userData。
例子:
const Dashboard = () => {
const { userData } = useContext(AppContext);
return (
<div>
<Nav />
<div id='dashboard'>
<div id='title' className='mt-[38px] ml-[11%]'>
{userData
? (
<div className='h2'>Good morning, { userData.user_info.first_name }!</div>
) : (
<div>No user data</div>
)
}
</div>
</div>
</div>
);
};
Run Code Online (Sandbox Code Playgroud)
inconsole.log("App Load")位于App主要组件主体中。这是无意的副作用。如果您想在App安装组件时记录日志,请使用安装useEffect挂钩。
例子:
useEffect(() => {
console.log("App Load");
}, []); // <-- empty dependency to run once on mount
Run Code Online (Sandbox Code Playgroud)
其他日志可能与 React 的StrictMode组件有关。具体请参阅检测意外副作用和确保可重用状态。该React.StrictMode组件有意双重调用某些组件方法/挂钩/等并双重安装该组件,以帮助您检测代码中的逻辑问题。这种情况仅发生在非生产版本中。
| 归档时间: |
|
| 查看次数: |
5630 次 |
| 最近记录: |