用 9 行代码保存你的 React 状态
这周末我正在研究Frontend Mentor的一个项目,并用 React Hooks 实现了主题切换器。我突然想到,在每次重新加载时保留我选择的主题会是一个很棒的功能。所以,让我们来构建一个可以实现这个功能的 Hooks 吧!
本文将带您完成创建可重用自定义钩子的过程,该钩子将我们的状态保存到本地存储。
入门
我们将创建一个名为 的自定义钩子,用于usePersistedState
将状态存储到本地存储。我们的函数应该接受一个键来存储状态,以及一个默认值(以防我们尚未保存任何内容)。它将返回相同的 API useState
(一个包含状态和更新函数的元组)。以下是我们的钩子签名:
function usePersistedState(key, defaultValue) {
// Some magic
return [state, setState];
}
即使我们将状态存储在本地存储中,我们也会在常规setState
调用中保留本地运行时副本。这样我们就可以触发重新渲染,并稍微缩短访问时间(访问本地存储可能没那么快)。最后,如果 localStorage 由于某种原因不可用,我们仍然有一个可用的钩子(尽管它不会持久化设置)。
function usePersistedState(key, defaultValue) {
const [state, setState] = React.useState(defaultValue);
return [state, setState];
}
将数据保存在本地存储中
接下来,让我们开始从本地存储读取数据!该localStorage
API 内置于您的浏览器中,您可以通过getItem
使用字符串键调用函数来访问值。
function usePersistedState(key, defaultValue) {
const [state, setState] = React.useState(
localStorage.getItem(key) || defaultValue
);
return [state, setState];
}
在这里,我们将调用的默认值设置useState
为 localStorage 中存储的内容,或者defaultValue
我们作为参数传入的内容。接下来,让我们实现更新本地存储的功能。我们将使用一个useEffect
钩子来实现这一点:
function usePersistedState(key, defaultValue) {
const [state, setState] = React.useState(
localStorage.getItem(key) || defaultValue
);
useEffect(() => {
localStorage.setItem(key, state);
}, [key, state]);
return [state, setState];
}
很聪明吧?每次更新状态时,都应该更新本地存储中的内容。如果键发生变化,我们也应该将当前状态存储在新的键下。
那么复数值呢?
虽然本地存储 API 很棒,但它只能存储字符串值。这有点麻烦——但我们可以通过在更新状态时将 JavaScript 对象序列化为 JSON(并返回)来绕过这个限制。我们使用JSON.parse
和JSON.stringify
函数来实现。
function usePersistedState(key, defaultValue) {
const [state, setState] = React.useState(
JSON.parse(localStorage.getItem(key)) || defaultValue
);
useEffect(() => {
localStorage.setItem(key, JSON.stringify(state));
}, [key, state]);
return [state, setState];
}
现在我们也支持复杂的数据结构!
最后的性能优化
我们目前的实现有一个性能陷阱——每次渲染都要从本地存储读取!更糟糕的是——我们这样做只是为了获取调用的初始值useState
!幸运的是,有办法解决这个问题。通过传入一个函数useState
,默认值只会运行一次!
让我们来实现它:
function usePersistedState(key, defaultValue) {
const [state, setState] = React.useState(
() => JSON.parse(localStorage.getItem(key)) || defaultValue
);
useEffect(() => {
localStorage.setItem(key, JSON.stringify(state));
}, [key, state]);
return [state, setState];
}
总结!
就这样!我们用几行代码实现了一段非常简洁的可复用代码。这非常适合用于本地设置,例如主题、字体大小,或者您希望在访问之间保留的其他 UI 状态。
这就是我最初提到的项目,它包含一个用于保存所选主题的钩子。快来试试吧!
您最喜欢的可重复使用的挂钩是什么?
文章来源:https://dev.to/selbekk/persisting-your-react-state-in-9-lines-of-code-9go