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

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

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

一、問(wèn)題場(chǎng)景:為什么數(shù)據(jù)會(huì)丟失?

我們先通過(guò)一個(gè)簡(jiǎn)單例子感受一下問(wèn)題:

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

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

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

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

基本實(shí)現(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īng)顟B(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
        })}
      />
      {/* 保存后刷新頁(yè)面,數(shù)據(jù)還在! */}
    </div>
  );
}

進(jìn)階:自動(dòng)過(guò)期和加密

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

  set(key, value, ttl = null) {
    const item = {
      value,
      timestamp: Date.now(),
      ttl
    };
    
    // 簡(jiǎn)單加密(生產(chǎn)環(huán)境應(yīng)使用更安全的方案)
    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));
      
      // 檢查是否過(guò)期
      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小時(shí)過(guò)期

三、方案二:sessionStorage(標(biāo)簽頁(yè)級(jí)別)

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];
}

// 特性:不同標(biāo)簽頁(yè)數(shù)據(jù)隔離,關(guān)閉標(biāo)簽頁(yè)自動(dòng)清除

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

當(dāng)需要存儲(chǔ)大量結(jié)構(gòu)化數(shù)據(jù)時(shí),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ù)(分享友好型)

適合篩選條件等需要分享的場(chǎng)景:

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會(huì)顯示 ?filters=%7B%22status%22%3A%22active%22%7D
function FilterComponent() {
  const [filters, setFilters] = useURLState('filters', { status: 'all' });
  
  // 分享當(dāng)前URL,別人打開(kāi)能看到同樣的篩選結(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ù)持久化流程圖

小量簡(jiǎn)單數(shù)據(jù)

標(biāo)簽頁(yè)隔離數(shù)據(jù)

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

可分享狀態(tài)

全局狀態(tài)管理

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

八、性能與安全最佳實(shí)踐

1. 防抖保存避免頻繁寫(xiě)入

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ù)量時(shí))

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

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

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

3. 安全存儲(chǔ)敏感信息

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

// 應(yīng)該:使用HttpOnly Cookie或臨時(shí)內(nèi)存存儲(chǔ)

九、方案對(duì)比選擇指南

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

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

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

總結(jié)

React數(shù)據(jù)持久化沒(méi)有銀彈,關(guān)鍵在于根據(jù)場(chǎng)景選擇合適的方案

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

記住一個(gè)原則:敏感信息永遠(yuǎn)不要在前端持久化!token、密碼等應(yīng)該通過(guò)HttpOnly Cookie或后端session管理。

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

相關(guān)文章

  • React組件對(duì)子組件children進(jìn)行加強(qiáng)的方法

    React組件對(duì)子組件children進(jìn)行加強(qiáng)的方法

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

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

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

    React如何利用相對(duì)于根目錄進(jìn)行引用組件詳解

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

    React處理復(fù)雜圖片樣式的方法詳解

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

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

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

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

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

    簡(jiǎn)易的redux?createStore手寫(xiě)實(shí)現(xiàn)示例

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

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

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

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

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

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

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

最新評(píng)論

仁寿县| 武宣县| 来安县| 武汉市| 冕宁县| 青田县| 鄂托克前旗| 加查县| 达州市| 外汇| 蒙山县| 武邑县| 黔东| 安远县| 赫章县| 泽州县| 贵定县| 沙湾县| 巴彦淖尔市| 双流县| 扶风县| 安福县| 博罗县| 乌拉特前旗| 鹰潭市| 驻马店市| 延吉市| 保靖县| 中山市| 扶风县| 屯门区| 白银市| 普兰店市| 惠水县| 巫山县| 江北区| 柳江县| 南雄市| 蒲城县| 凉城县| 射阳县|