紀錄在 React strict mode 之下,透過 Local Storage 儲存 state 資料,並在 refresh 頁面後保留資料的方式
一般在 refresh 頁面後,component 的 state 資料就會被還原回初始值; 然而在某些情況,如: 第三方登入,會將頁面跳轉到第三方自家的認證頁面,並在成功後跳轉回 APP 頁面,這樣的行為就相當於 refresh 頁面,但有時候會希望不透過 API 將暫時資料儲存在 server,這時候最直覺的做法就是將資料儲存在 Local Storage。
一段簡易的使用者資料如下:
1 2 3 4 5 6 7 8 9
| const App = () => { const [user, setUser] = useState({ name: "" });
return ( <div> <button>Google 登入</button> </div> ); };
|
如果要與 Local Storage 的資料同步,就會在頁面載入時,取得 Local Storage 的資料,並在資料更新時同步更新 Local Storage 的資料,所以就可以透過 useEffect
執行這兩個動作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const App = () => { const [user, setUser] = useState({ name: "" });
useEffect(() => { setUser(JSON.parse(localStorage.getItem("user"))); }, []);
useEffect(() => { if (user) localStorage.setItem("user", JSON.stringify(user)); }, [user]);
return ( <div> <button>Google 登入</button> </div> ); };
|
Strict Mode
以上的作法在一般情況執行沒有問題,但如果在 React 18 strict mode 的環境下執行,就會發現資料並沒有被儲存到,但透過 console.log
印出資料就會發現,並不是資料沒有被更新到 Local Stroage,而是更新後資料又被初始值所覆蓋
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const App = () => { const [user, setUser] = useState({ name: "" });
useEffect(() => { console.log("get", JSON.parse(localStorage.getItem("user")).name); setUser(JSON.parse(localStorage.getItem("user"))); }, []);
useEffect(() => { console.log("set", user.name); if (user) localStorage.setItem("user", JSON.stringify(user)); }, [user]);
return ( <div> <button>Google 登入</button> </div> ); };
|
原因是在 strict mode 之下,component 會被 render 兩次,而 state 從無到初始資料的過程就會觸發更新 Local Storage 的動作,所以在取得新的資料後,又把初始資料更新回去; 而為解決這種情況,除了依賴其他第三方套件之外,可以判斷如果 Local Storage 有資料,就直接以它為初始資料
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const App = () => { const [user, setUser] = useState(() => localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : { name: "" } );
useEffect(() => { console.log("set", user.name); if (user) localStorage.setItem("user", JSON.stringify(user)); }, [user]);
return ( <div> <button>Google 登入</button> </div> ); };
|
資料參考
Why is localStorage getting cleared whenever I refresh the page?
5 Methods to Persisting State Between Page Reloads in React