最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React頁面刷新數(shù)據(jù)不丟失的五種方案

 更新時間:2025年12月16日 09:50:47   作者:北辰alk  
前端開發(fā)中,相信大家都遇到過這樣的痛點:頁面一刷新,辛辛苦苦填的表單數(shù)據(jù)沒了,精心選擇的篩選條件重置了,今天我們就來深入探討React中數(shù)據(jù)持久化的5大核心方案,從簡單到復雜,幫你徹底解決這個難題,需要的朋友可以參考下

一、問題場景:為什么數(shù)據(jù)會丟失?

我們先通過一個簡單例子感受一下問題:

function UserForm() {
  const [formData, setFormData] = useState({
    username: '',
    email: '',
    preferences: {
      theme: 'light',
      notifications: true
    }
  });

  // 用戶輸入數(shù)據(jù)...
  // 頁面刷新 → 所有數(shù)據(jù)歸零 ??
  
  return (
    <form>
      <input 
        value={formData.username}
        onChange={(e) => setFormData({...formData, username: e.target.value})}
      />
      {/* 其他表單項 */}
    </form>
  );
}

數(shù)據(jù)丟失的根本原因是:React狀態(tài)(state)存儲在內(nèi)存中,頁面刷新時內(nèi)存被清空。

二、方案一:localStorage(最常用)

基本實現(xiàn)

function useLocalStorage(key, initialValue) {
  // 從localStorage讀取初始值
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });

  // 更新狀態(tài)并保存到localStorage
  const setValue = (value) => {
    try {
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.error(error);
    }
  };

  return [storedValue, setValue];
}

// 使用示例
function PersistentForm() {
  const [userData, setUserData] = useLocalStorage('user_form_data', {
    username: '',
    email: '',
    theme: 'light'
  });

  return (
    <div>
      <input
        value={userData.username}
        onChange={(e) => setUserData({
          ...userData, 
          username: e.target.value
        })}
      />
      {/* 保存后刷新頁面,數(shù)據(jù)還在! */}
    </div>
  );
}

進階:自動過期和加密

class SecureStorage {
  constructor(namespace) {
    this.namespace = namespace;
  }

  set(key, value, ttl = null) {
    const item = {
      value,
      timestamp: Date.now(),
      ttl
    };
    
    // 簡單加密(生產(chǎn)環(huán)境應使用更安全的方案)
    const encrypted = btoa(JSON.stringify(item));
    localStorage.setItem(`${this.namespace}:${key}`, encrypted);
  }

  get(key) {
    const encrypted = localStorage.getItem(`${this.namespace}:${key}`);
    if (!encrypted) return null;

    try {
      const item = JSON.parse(atob(encrypted));
      
      // 檢查是否過期
      if (item.ttl && Date.now() - item.timestamp > item.ttl) {
        this.remove(key);
        return null;
      }
      
      return item.value;
    } catch {
      return null;
    }
  }
}

// 使用
const storage = new SecureStorage('myApp');
storage.set('token', 'abc123', 1000 * 60 * 60); // 1小時過期

三、方案二:sessionStorage(標簽頁級別)

function useSessionStorage(key, initialValue) {
  const [state, setState] = useState(() => {
    // 只在客戶端執(zhí)行
    if (typeof window === 'undefined') return initialValue;
    
    const stored = sessionStorage.getItem(key);
    return stored ? JSON.parse(stored) : initialValue;
  });

  useEffect(() => {
    sessionStorage.setItem(key, JSON.stringify(state));
  }, [key, state]);

  return [state, setState];
}

// 特性:不同標簽頁數(shù)據(jù)隔離,關閉標簽頁自動清除

四、方案三:IndexedDB(大量數(shù)據(jù))

當需要存儲大量結(jié)構(gòu)化數(shù)據(jù)時,IndexedDB是更好的選擇:

class IndexedDBService {
  constructor(dbName, version) {
    this.dbName = dbName;
    this.version = version;
    this.db = null;
  }

  async open() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.dbName, this.version);

      request.onupgradeneeded = (event) => {
        const db = event.target.result;
        if (!db.objectStoreNames.contains('state')) {
          db.createObjectStore('state', { keyPath: 'key' });
        }
      };

      request.onsuccess = (event) => {
        this.db = event.target.result;
        resolve();
      };

      request.onerror = (event) => reject(event.target.error);
    });
  }

  async set(key, value) {
    const transaction = this.db.transaction(['state'], 'readwrite');
    const store = transaction.objectStore('state');
    store.put({ key, value });
  }

  async get(key) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction(['state'], 'readonly');
      const store = transaction.objectStore('state');
      const request = store.get(key);

      request.onsuccess = () => resolve(request.result?.value);
      request.onerror = () => reject(request.error);
    });
  }
}

// React Hook封裝
function useIndexedDB(key, initialValue) {
  const [value, setValue] = useState(initialValue);
  const [db, setDb] = useState(null);

  useEffect(() => {
    const initDB = async () => {
      const dbService = new IndexedDBService('AppDB', 1);
      await dbService.open();
      setDb(dbService);
      
      const stored = await dbService.get(key);
      if (stored) setValue(stored);
    };
    
    initDB();
  }, [key]);

  const updateValue = async (newValue) => {
    setValue(newValue);
    if (db) await db.set(key, newValue);
  };

  return [value, updateValue];
}

五、方案四:URL參數(shù)(分享友好型)

適合篩選條件等需要分享的場景:

import { useHistory, useLocation } from 'react-router-dom';

function useURLState(key, initialValue) {
  const location = useLocation();
  const history = useHistory();
  
  const queryParams = new URLSearchParams(location.search);
  
  const [value, setValue] = useState(() => {
    const param = queryParams.get(key);
    return param ? JSON.parse(decodeURIComponent(param)) : initialValue;
  });

  const setURLValue = (newValue) => {
    setValue(newValue);
    
    // 更新URL參數(shù)
    const newParams = new URLSearchParams(location.search);
    newParams.set(key, encodeURIComponent(JSON.stringify(newValue)));
    
    history.replace({
      pathname: location.pathname,
      search: newParams.toString()
    });
  };

  return [value, setURLValue];
}

// 使用:URL會顯示 ?filters=%7B%22status%22%3A%22active%22%7D
function FilterComponent() {
  const [filters, setFilters] = useURLState('filters', { status: 'all' });
  
  // 分享當前URL,別人打開能看到同樣的篩選結(jié)果
}

六、方案五:Redux + 持久化中間件

// store/persistConfig.js
const persistConfig = {
  key: 'root',
  storage, // 可以是localStorage、sessionStorage等
  whitelist: ['auth', 'userPreferences'], // 只持久化這些reducer
  blacklist: ['temporaryData'], // 不持久化這些
  transforms: [
    // 數(shù)據(jù)轉(zhuǎn)換(如加密)
    encryptTransform({
      secretKey: process.env.REACT_APP_ENCRYPT_KEY
    })
  ]
};

// store/index.js
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';

const persistedReducer = persistReducer(persistConfig, rootReducer);

export const store = createStore(persistedReducer);
export const persistor = persistStore(store);

// App.js
import { PersistGate } from 'redux-persist/integration/react';

function App() {
  return (
    <Provider store={store}>
      <PersistGate loading={<LoadingSpinner />} persistor={persistor}>
        <MainApp />
      </PersistGate>
    </Provider>
  );
}

七、數(shù)據(jù)持久化流程圖

小量簡單數(shù)據(jù)

標簽頁隔離數(shù)據(jù)

大量結(jié)構(gòu)化數(shù)據(jù)

可分享狀態(tài)

全局狀態(tài)管理

頁面刷新數(shù)據(jù)恢復決策localStoragesessionStorageIndexedDBURL參數(shù)Redux持久化快速讀取
5-10MB限制會話級存儲
標簽頁獨立大容量存儲
異步操作可分享狀態(tài)
URL可見集成Redux
狀態(tài)同步數(shù)據(jù)恢復完成

八、性能與安全最佳實踐

1. 防抖保存避免頻繁寫入

function useDebouncedPersist(key, value, delay = 1000) {
  useEffect(() => {
    const timer = setTimeout(() => {
      localStorage.setItem(key, JSON.stringify(value));
    }, delay);
    
    return () => clearTimeout(timer);
  }, [key, value, delay]);
}

2. 數(shù)據(jù)壓縮(大數(shù)據(jù)量時)

import { compress, decompress } from 'lz-string';

const compressData = (data) => {
  return compress(JSON.stringify(data));
};

const decompressData = (compressed) => {
  return JSON.parse(decompress(compressed));
};

3. 安全存儲敏感信息

// 永遠不要這樣做!
localStorage.setItem('token', rawToken);

// 應該:使用HttpOnly Cookie或臨時內(nèi)存存儲

九、方案對比選擇指南

方案容量生命周期使用場景優(yōu)缺點
localStorage5-10MB永久用戶偏好設置簡單易用,但同步阻塞
sessionStorage5-10MB標簽頁臨時表單數(shù)據(jù)標簽頁隔離,關閉即失
IndexedDB大量永久離線應用數(shù)據(jù)異步大容量,API復雜
URL參數(shù)受限頁面級別篩選條件分享可分享,但有長度限制
Redux持久化靈活可配置全局狀態(tài)管理集成度高,需額外配置

十、實戰(zhàn):完整表單持久化示例

function PersistentForm() {
  // 綜合使用多種方案
  const [basicInfo, setBasicInfo] = useLocalStorage('form_basic', {});
  const [tempData, setTempData] = useSessionStorage('form_temp', {});
  const [filters, setFilters] = useURLState('form_filters', {});
  
  // 自動保存草稿
  useDebouncedPersist('form_draft', {
    basicInfo,
    tempData
  }, 2000);
  
  // 離開頁面提示
  useBeforeUnload(() => {
    if (hasUnsavedChanges) {
      return '您有未保存的更改,確定要離開嗎?';
    }
  });
  
  return (
    <div>
      {/* 表單內(nèi)容 */}
      <button onClick={clearAllStorage}>
        清空所有持久化數(shù)據(jù)
      </button>
    </div>
  );
}

總結(jié)

React數(shù)據(jù)持久化沒有銀彈,關鍵在于根據(jù)場景選擇合適的方案

  1. 1. 用戶設置 → localStorage
  2. 2. 臨時表單 → sessionStorage
  3. 3. 離線數(shù)據(jù) → IndexedDB
  4. 4. 分享狀態(tài) → URL參數(shù)
  5. 5. 全局狀態(tài) → Redux持久化

記住一個原則:敏感信息永遠不要在前端持久化!token、密碼等應該通過HttpOnly Cookie或后端session管理。

以上就是React頁面刷新數(shù)據(jù)不丟失的五種方案的詳細內(nèi)容,更多關于React頁面刷新數(shù)據(jù)不丟失的資料請關注腳本之家其它相關文章!

相關文章

  • React組件對子組件children進行加強的方法

    React組件對子組件children進行加強的方法

    這篇文章主要給大家介紹了關于React組件中對子組件children進行加強的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用React具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-06-06
  • 使用react在修改state中的數(shù)組和對象數(shù)據(jù)的時候(setState)

    使用react在修改state中的數(shù)組和對象數(shù)據(jù)的時候(setState)

    這篇文章主要介紹了使用react在修改state中的數(shù)組和對象數(shù)據(jù)的時候(setState),具有很好的參考價值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • React如何利用相對于根目錄進行引用組件詳解

    React如何利用相對于根目錄進行引用組件詳解

    這篇文章主要給大家介紹了關于React如何使用相對于根目錄進行引用組件的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2017-10-10
  • React處理復雜圖片樣式的方法詳解

    React處理復雜圖片樣式的方法詳解

    這篇文章主要為大家詳細介紹了React處理復雜圖片樣式的方法,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-04-04
  • react?hooks?d3實現(xiàn)企查查股權(quán)穿透圖結(jié)構(gòu)圖效果詳解

    react?hooks?d3實現(xiàn)企查查股權(quán)穿透圖結(jié)構(gòu)圖效果詳解

    這篇文章主要為大家介紹了react?hooks?d3實現(xiàn)企查查股權(quán)穿透圖結(jié)構(gòu)圖效果詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • React中組件復用的方式總結(jié)

    React中組件復用的方式總結(jié)

    這篇文章主要為大家詳細介紹了Mixin、HOC、Render?Props、Hooks這四種組件間復用的方式,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2023-06-06
  • 簡易的redux?createStore手寫實現(xiàn)示例

    簡易的redux?createStore手寫實現(xiàn)示例

    這篇文章主要介紹了簡易的redux?createStore手寫實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • 在React項目中使用iframe嵌入一個網(wǎng)站的步驟

    在React項目中使用iframe嵌入一個網(wǎng)站的步驟

    本文介紹了如何在React項目中通過iframe嵌入百度網(wǎng)站的步驟,首先創(chuàng)建一個Baidu.js組件,并在該組件中設置iframe來加載百度,然后在App.js中引入并使用Baidu組件,還討論了因安全策略可能無法加載某些網(wǎng)站的問題,需要的朋友可以參考下
    2024-09-09
  • 想用好React的你必須要知道的一些事情

    想用好React的你必須要知道的一些事情

    現(xiàn)在最熱門的前端框架,毫無疑問是 React 。下面這篇文章主要給大家分享了關于想用好React的你必須要知道的一些事情,文中介紹的非常詳細,對大家具有一定參考學習價值,需要的朋友們下面來一起看看吧。
    2017-07-07
  • 基于react?vant實現(xiàn)彈窗搜索功能

    基于react?vant實現(xiàn)彈窗搜索功能

    這篇文章主要為大家詳細介紹了如何基于react?vant實現(xiàn)彈窗搜索功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-01-01

最新評論

南部县| 泾阳县| 永州市| 上饶市| 呼伦贝尔市| 定远县| 卫辉市| 当涂县| 库伦旗| 麻栗坡县| 察哈| 昌黎县| 柯坪县| 郑州市| 玛多县| 麻江县| 金门县| 云龙县| 利川市| 伽师县| 黑山县| 广东省| 耿马| 北流市| 东港市| 洪雅县| 元江| 全椒县| 江北区| 白山市| 丹江口市| 广西| 交城县| 祁门县| 宜良县| 湄潭县| 内丘县| 云梦县| 临潭县| 乌鲁木齐县| 海南省|