Skip to main content

React SWR: 让请求自动cache

· 9 min read
nFMOau

现代的 hooks 模型

在用户体验上,前端依然非常依赖和后端之间建立的网络链接。在网络环境良好的情况下,大部分 Web App 都可以提供较好的用户体验。但是随着移动化的浪潮,前端的 App 也越来越多被应用在小程序、h5 等移动环境中,而移动网络的不稳定性和 Web App 的即时渲染,都极大地影响了 Web App 的体验。

QcUwse

通过请求 hooks 对于请求的优化,前端应用更加独立。因为存在 cacheKey、Refetching 等机制,现在我们可以有新的角度去看待 Web App。这个时代下,Web App 更加独立,可以自身缓存一定的数据,也可以更快地响应用户的操作。通过增加静默请求和减少页面全刷新,使网络延迟和数据更新趋于无感。而这一点,hooks 和 diff 机制配合得天衣无缝。

0rfjSW

mutate(key)和 mutate()

在 React SWR 中,mutate 方法有两种调用方式:mutate(key)mutate()。它们的主要区别在于作用范围和使用场景。以下是详细的解释:

1. mutate(key)

mutate(key) 是一个全局方法,用于操作特定的缓存键(key)。你可以通过指定 key 来精确地操作某个缓存数据。

参数

  • key:指定要操作的缓存键。
  • data(可选):如果提供,可以直接更新缓存数据。
  • options(可选):配置选项,例如 { revalidate: true }

作用范围

  • 全局作用mutate(key) 作用于全局缓存,可以跨组件使用。
  • 精确操作:通过指定 key,可以精确地操作某个缓存数据。

示例

import useSWR, { mutate } from 'swr';

const fetcher = url => fetch(url).then(res => res.json());

function MyComponent() {
const { data, error } = useSWR('/api/data', fetcher);

const updateData = async newData => {
try {
// 调用 update API
await fetch('/api/update', {
method: 'POST',
body: JSON.stringify(newData),
headers: { 'Content-Type': 'application/json' },
});

// 重新验证指定的缓存键
mutate('/api/data');
} catch (err) {
console.error('Update failed:', err);
}
};

if (error) return <div>Failed to load</div>;
if (!data) return <div>Loading...</div>;

return (
<div>
<div>{JSON.stringify(data)}</div>
<button onClick={() => updateData({ key: 'value' })}>Update Data</button>
</div>
);
}

2. mutate()

mutate() 是一个绑定到 useSWR 的方法,用于操作当前组件中使用的缓存数据。它不需要显式指定 key,因为 key 已经在 useSWR 中定义。

参数

  • data(可选):如果提供,可以直接更新缓存数据。
  • options(可选):配置选项,例如 { revalidate: true }

作用范围

  • 局部作用mutate() 作用于当前组件中使用的缓存数据。
  • 简化操作:不需要显式指定 key,直接操作当前组件的缓存。

示例

import useSWR, { mutate } from 'swr';

const fetcher = url => fetch(url).then(res => res.json());

function MyComponent() {
const { data, error, mutate } = useSWR('/api/data', fetcher);

const updateData = async newData => {
try {
// 调用 update API
await fetch('/api/update', {
method: 'POST',
body: JSON.stringify(newData),
headers: { 'Content-Type': 'application/json' },
});

// 重新验证当前组件的缓存数据
mutate();
} catch (err) {
console.error('Update failed:', err);
}
};

if (error) return <div>Failed to load</div>;
if (!data) return <div>Loading...</div>;

return (
<div>
<div>{JSON.stringify(data)}</div>
<button onClick={() => updateData({ key: 'value' })}>Update Data</button>
</div>
);
}

总结

  • mutate(key)

    • 全局作用:可以跨组件操作指定的缓存键。
    • 精确操作:需要显式指定 key
    • 适用场景:当你需要在多个组件中操作同一个缓存键时,或者需要操作全局缓存时。
  • mutate()

    • 局部作用:只作用于当前组件中使用的缓存数据。
    • 简化操作:不需要显式指定 key
    • 适用场景:当你只需要在当前组件中操作缓存数据时,使用 mutate() 更为方便。

选择哪种方式取决于你的具体需求。如果需要跨组件操作缓存,建议使用 mutate(key);如果只需要在当前组件中操作缓存,使用 mutate() 更为简洁。

revalidate 是干什用的?

在 React SWR 中,revalidate 是一个非常重要的选项,用于控制数据的重新验证行为。它允许你手动触发对缓存数据的重新获取,从而确保数据的最新性。

作用

revalidate 的主要作用是强制重新获取数据,即使数据已经存在于缓存中。这在以下几种场景中非常有用:

  1. 数据更新后:当你通过 update API 修改了数据,需要重新获取最新的数据时。
  2. 手动刷新:用户触发了手动刷新操作,需要重新获取数据。
  3. 定时刷新:在某些情况下,你可能希望定期重新获取数据以保持数据的最新性。

使用方法

revalidate 可以在 mutate 方法中使用,也可以在 useSWR 的配置中使用。

1. 在 mutate 中使用 revalidate

当你调用 mutate 方法时,可以通过 options 参数设置 revalidatetrue,从而触发重新获取数据。

import useSWR, { mutate } from 'swr';

const fetcher = url => fetch(url).then(res => res.json());

function MyComponent() {
const { data, error } = useSWR('/api/data', fetcher);

const updateData = async newData => {
try {
// 调用 update API
await fetch('/api/update', {
method: 'POST',
body: JSON.stringify(newData),
headers: { 'Content-Type': 'application/json' },
});

// 重新验证数据
mutate('/api/data', undefined, { revalidate: true });
} catch (err) {
console.error('Update failed:', err);
}
};

if (error) return <div>Failed to load</div>;
if (!data) return <div>Loading...</div>;

return (
<div>
<div>{JSON.stringify(data)}</div>
<button onClick={() => updateData({ key: 'value' })}>Update Data</button>
</div>
);
}

2. 在 useSWR 中使用 revalidate

你也可以在 useSWR 的配置中设置 revalidate 选项,从而控制数据的自动重新验证行为。

import useSWR from 'swr';

const fetcher = url => fetch(url).then(res => res.json());

function MyComponent() {
const { data, error, mutate } = useSWR('/api/data', fetcher, {
revalidateOnMount: true, // 每次组件加载时重新验证
revalidateOnFocus: true, // 窗口重新聚焦时重新验证
revalidateOnReconnect: true, // 网络重新连接时重新验证
});

const updateData = async newData => {
try {
// 调用 update API
await fetch('/api/update', {
method: 'POST',
body: JSON.stringify(newData),
headers: { 'Content-Type': 'application/json' },
});

// 重新验证数据
mutate();
} catch (err) {
console.error('Update failed:', err);
}
};

if (error) return <div>Failed to load</div>;
if (!data) return <div>Loading...</div>;

return (
<div>
<div>{JSON.stringify(data)}</div>
<button onClick={() => updateData({ key: 'value' })}>Update Data</button>
</div>
);
}

常见的 revalidate 选项

  • revalidateOnMount:组件加载时是否重新验证数据。默认值为 true
  • revalidateOnFocus:窗口重新聚焦时是否重新验证数据。默认值为 true
  • revalidateOnReconnect:网络重新连接时是否重新验证数据。默认值为 true
  • revalidateIfStale:如果数据过期(isStaletrue),是否重新验证数据。默认值为 true
  • revalidateOnInterval:设置一个时间间隔(毫秒),每隔这个时间重新验证数据。例如:revalidateOnInterval: 30000(每 30 秒重新验证一次)。

总结

revalidate 是 React SWR 中一个非常强大的功能,用于控制数据的重新验证行为。通过合理使用 revalidate,你可以确保数据的最新性,同时避免不必要的网络请求,提升应用的性能和用户体验。

参考资料

  1. https://swr.vercel.app/docs/mutation
  2. 从 SWR 开始 — 一窥现代请求 hooks 设计模型
  3. 【第1795期】SWR:最具潜力的 React Hooks 数据请求库