学习用自己的自定义useLocalStorage钩子在React中使用本地存储

278 阅读4分钟

我们可能会用到的一个浏览器端存储数据的工具是本地存储。在这篇文章中,我们将通过滚动我们自己的useLocalStorage钩子在React中使用本地存储。

更新

基于这篇越来越受欢迎的博文,我创建了一个npm模块,uselocalstorage 。请查看它,让我知道你的想法,并欢迎你为它做出贡献!

用npm安装。

npm install use-local-storage

用yarn安装。

yarn add use-local-storage

我们的方法

为了解决这个问题,让我们把它分解成几块。

  1. 提供一个本地存储的密钥。本地存储是通过键值对工作的,所以我们希望能够为我们的存储数据提供一个key
  2. 提供一个默认值。如果在所提供的key ,本地存储中没有现有的数据,我们将希望能够为我们的数据提供一个defualtValue
  3. 将本地存储值加载到状态中(如果不存在本地存储值,则为默认值)。我们仍然会在我们的应用程序中维护有状态的信息,所以我们仍然可以使用useState 钩。这里的区别是,在我们考虑用户提供的defaultValue 之前,我们将使用本地存储值(如果它存在)。
  4. 将有状态数据保存到本地存储。当我们的有状态数据发生变化时,我们要确保本地存储是最新的。因此,在我们的变量发生任何变化时,让我们运行一个效果来同步本地存储。
  5. 暴露状态变量和一个setter。和useState 钩子一样,我们的useLocalStorage 钩子将返回一个2元素的数组。第一个元素是变量,第二个元素是该变量的设置器。

创建钩子

让我们来创建这个钩子!如上所述,该钩子将接受两个输入:key ,它将用于localStoragedefaultValue ,它将用于localStorage ,即使还没有任何东西。

useLocalStorage.js

export const useLocalStorage = (key, defaultValue) => {};

接下来,让我们在提供的key 下加载localStorage 中的任何数据。

export const useLocalStorage = (key, defaultValue) => {
  const stored = localStorage.getItem(key);
};

现在我们知道,我们的有状态变量的初始值将是这个stored 值。然而,如果在提供的key 下,localStorage 中还没有任何数据,我们将默认为用户提供的defaultValue

注意:由于localStorage 数据是以字符串形式存储的,我们要确保从那里检索到的任何数据都是JSON.parse

export const useLocalStorage = (key, defaultValue) => {
  const stored = localStorage.getItem(key);
  const initial = stored ? JSON.parse(stored) : defaultValue;
};

现在我们有了状态的initial 值,我们可以使用常规的useState 钩子格式,返回我们的状态变量和它的设置器。

import { useState } from 'react';

export const useLocalStorage = (key, defaultValue) => {
  const stored = localStorage.getItem(key);
  const initial = stored ? JSON.parse(stored) : defaultValue;
  const [value, setValue] = useState(initial);
  return [value, setValue];
};

几乎完成了!我们还有一个尚未满足的要求:当数据被改变时,我们需要将其保存回localStorage 。我喜欢在useEffect 钩子中做这个,当value 发生变化时,钩子会被触发。

import { useState, useEffect } from 'react';

export const useLocalStorage = (key, defaultValue) => {
  const stored = localStorage.getItem(key);
  const initial = stored ? JSON.parse(stored) : defaultValue;
  const [value, setValue] = useState(initial);

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

  return [value, setValue];
};

我们有了它!每当value 发生变化时,我们的效果就会运行,这意味着我们将把localStorage 项目设置为我们的valueJSON.stringify 。请注意,所提供的key 是我们的效果的一个依赖项,所以为了完整起见,我们把它包括在依赖项数组中,尽管我们并不指望它真的会改变。

测试我们的新钩子

让我们来测试一下我们的钩子吧我们将创建一个简单的组件,它有一个文本输入,其值是基于我们的useLocalStorage 钩子。

App.jsx

import React from 'react';
import { useLocalStorage } from './useLocalStorage';

function App() {
  const [name, setName] = useLocalStorage('username', 'John');
  return (
    <input
      value={name}
      onChange={(e) => {
        setName(e.target.value);
      }}
    />
  );
}

export default App;

现在让我们运行我们的应用程序。我们可以看到,当我们第一次运行这个应用程序时,我们的有状态的name 变量被默认为字符串John 。然而,当我们改变值,然后刷新页面时,我们现在默认为持久化的值,localStorage

image.png

成功了!