0


前端离线存储能力:如何在 React 中巧妙运用IndexedDB

前言

当我们开发复杂的Web应用时,常常需要在客户端存储大量数据。你可能听过

localStorage

或者

sessionStorage

,但它们在存储空间和功能上都有限。而今天我们要聊的,是一个功能更强大的技术:IndexedDB

IndexedDB 是什么

IndexedDB是一个运行在浏览器中的非关系型数据库。它让你能够存储大量的数据,并具有高性能的查询能力。不像localStorage只能存储字符串,IndexedDB可以存储各种类型的数据,比如文件、Blob,以及你可以想到的其他各种类型。

IndexedDB 的能力

  1. 存储大数据量: 它可以存储比 localStorage更多的数据,而且没有固定的大小限制,往往是根据用户磁盘大小的一定百分比。
  2. 复杂数据存储: 能够存储更加复杂的数据类型。
  3. 查询性能优越: IndexedDB支持索引,你可以建立索引快速检索数据,而不用遍历整个数据库。
  4. 离线应用程序: 在用户没有网的时候,应用还是可以访问到之前存储的数据。
  5. 事务支持: IndexedDB支持事务,你可以进行复杂的数据操作,而且还有回滚的能力。
  6. 异步: 所有操作都是异步的,这也意味着它不会阻塞你的UI线程,用户体验更好。

在 React 项目中使用 IndexedDB

好,现在我们知道了IndexedDB是个好东西,那如何在React中使用它呢?

这篇文章会介绍使用IndexedDB的两种方式。

一、原生方式

我们来创建一个简单的React hook来展示如何使用原生的IndexedDB API。

import{ useEffect, useState }from'react';constuseIndexedDB=(dbName, storeName)=>{const[db, setDb]=useState(null);useEffect(()=>{const request = indexedDB.open(dbName,1);

    request.onerror=(event)=>{
      console.error('Database error:', event.target.errorCode);};

    request.onsuccess=(event)=>{setDb(event.target.result);};

    request.onupgradeneeded=(event)=>{const db = event.target.result;
      db.createObjectStore(storeName,{keyPath:'id',autoIncrement:true});};},[dbName, storeName]);constaddData=(data)=>{const transaction = db.transaction([storeName],'readwrite');const store = transaction.objectStore(storeName);
    store.add(data);};return[db, addData];};

这个Hook非常基础,它可以打开数据库,并允许你向数据库中添加数据。

二、使用localForage

现在让我们看看如何使用

localForage

——一个快速简便的本地存储库,以更简洁的方式使用IndexedDB。首先,你需要安装

localForage

npminstall localforage

现在你可以用它来简化IndexedDB的操作了:

import localForage from'localforage';

localForage.setItem('somekey','somevalue').then(()=>{return localForage.getItem('somekey');}).then((value)=>{// 这里是我们的数据
        console.log(value);}).catch((err)=>{// 出错了!
        console.error(err);});
localForage.setItem()

localForage.getItem()

都返回Promise,这让它们可以很方便地与async/await一起使用。

import React,{ useEffect }from'react';import localForage from'localforage';constApp=()=>{useEffect(()=>{// 保存数据asyncfunctionstoreData(){try{await localForage.setItem('user',{id:1,name:'John Doe'});// 读取数据const userData =await localForage.getItem('user');
        console.log(userData);// => {id: 1, name: "John Doe"}}catch(err){// 错误处理
        console.error(err);}}storeData();},[]);return(<div><h1>Welcome to IndexedDB with localForage</h1></div>);};exportdefault App;

在这个例子中,我们创建了一个名为

App

的React组件,在组件的

useEffect

Hook中,我们写了一个名为

storeData

async

函数来异步交互IndexedDB。我们先使用

setItem

方法向IndexedDB中存入数据,然后用

getItem

读取这些数据,并把它们打印出来。

localForage

支持回调和

Promise

形式的API,这使得它非常容易在现代JavaScript或TypeScript应用程序中使用。它也会自动根据浏览器的支持情况后退到使用WebSQL或localStorage,这为你的应用程序提供了更好的兼容性。

实战

接下来让我们试着构建一个小型的待办事项应用,这个应用将会使用React和IndexedDB原生API来存储数据。

第一步:创建一个IndexedDB数据库和对象存储

创建React应用的入口文件

App.js

并编写以下内容:

import React,{ useState, useEffect }from'react';functionApp(){const[db, setDb]=useState(null);const[todos, setTodos]=useState([]);const[task, setTask]=useState('');useEffect(()=>{let request = indexedDB.open('todoDB',1);

    request.onerror=(e)=>{
      console.log('Error opening db', e);};

    request.onsuccess=(e)=>{setDb(e.target.result);};

    request.onupgradeneeded=(e)=>{let db = e.target.result;let store = db.createObjectStore('todos',{keyPath:'id',autoIncrement:true});
      store.createIndex('task','task',{unique:false});};},[]);// ...后续内容将会增加到这里...return(<div><h1>Todo App with IndexedDB</h1>{/* 待办事项表单和列表展示将会在这里添加 */}</div>);}exportdefault App;

第二步:实现添加和显示待办事项的功能

现在,我们在组件内实现添加新的待办事项到IndexedDB中和从数据库中读取待办事项列表的功能。

更新

App.js

,添加以下内容:

// ...之前的代码...functionaddTodo(){const transaction = db.transaction(['todos'],'readwrite');const store = transaction.objectStore('todos');let request = store.add({ task });

  request.onsuccess=()=>{
    console.log('Task added');setTask('');// 清空输入loadTodos();// 重新加载待办事项列表};}functionloadTodos(){let transaction = db.transaction(['todos'],'readonly');let store = transaction.objectStore('todos');let request = store.openCursor();let todos =[];

  request.onsuccess=(e)=>{let cursor = e.target.result;if(cursor){
      todos.push(cursor.value);
      cursor.continue();}else{setTodos(todos);}};}// 确保数据被加载useEffect(()=>{if(db){loadTodos();}},[db]);// ...之前的代码...return(<div>{/* 其他代码 */}<input type="text" value={task} onChange={(e)=>setTask(e.target.value)}/><button onClick={addTodo}>Add Task</button><ul>{todos.map((todo)=>(<li key={todo.id}>{todo.task}</li>))}</ul></div>);// ...之前的代码...

以上代码完成了以下功能:

  • 通过 useEffect钩子创建或打开一个名为 todoDB的IndexedDB数据库,如果不存在,就会创建一个名叫 todos的对象存储。
  • 使用 addTodo函数来将新任务添加进数据库。
  • 使用 loadTodos函数查询IndexedDB中的所有待办事项,并将它们设置到组件状态中,以便可以在React组件中显示这些待办事项。
  • 提供了一个简单的表单,可以输入新的待办事项并添加到列表中。

此时,我们已经拥有了一个可以使用IndexedDB存储数据的基本的待办事项应用。当然,实际应用中还需要很多增强,比如错误处理、用户输入验证以及待办事项的删除和编辑功能等。但这个例子足以说明如何在React中直接使用IndexedDB,以及开发可以持久存储用户数据的Web应用程序。

结论

IndexedDB的确是一种功能强大的工具,尤其适合那些需要存储和操作大量和/或复杂数据的Web应用程序。不过,记住它的API并不像localStorage那么简单直接,所以在大多数情况下,使用

localForage

等库可以大大简化这个过程。


本文转载自: https://blog.csdn.net/m0_37890289/article/details/135541578
版权归原作者 乐闻x 所有, 如有侵权,请联系我们删除。

“前端离线存储能力:如何在 React 中巧妙运用IndexedDB”的评论:

还没有评论