WHAT - SWR(stale-while-revalidate)HTTP 缓存失效策略 - 请求方案

目录

  • 介绍
    • 传统数据请求的 React 代码示例
    • SWR 的 React 代码示例
    • SWR 的优势和不同之处
  • 可复用组件
  • 真实示例
  • 特性解读
    • 自动重新请求
      • 1. 聚焦时重新请求
      • 2. 定期重新请求
      • 3. 重新连接时重新请求
    • 条件数据请求
      • 1. 按需请求
      • 2. 依赖请求
    • 数据更改
      • 1. 乐观更新
      • 2. 在数据更改后更新缓存
      • 3. 基于当前数据进行数据更改
      • 4. 更改多项数据
      • 5. 避免竞态条件
    • 订阅
    • 预请求

介绍

https://swr.vercel.app/zh-CN

SWR 是一个用于数据请求的 React Hooks 库,它的名字来源于 stale-while-revalidate,即利用缓存来提供即时响应并在后台更新数据的策略。

相比于传统的数据请求方法,SWR 具有以下优势:

传统数据请求的 React 代码示例

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const UserComponent = () => {
  const [userData, setUserData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await axios.get('https://api.example.com/user');
        setUserData(response.data);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    // Cleanup function if necessary
    return () => {
      // Cleanup logic
    };
  }, []);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  if (!userData) return null;

  return (
    <div>
      <h1>User Data</h1>
      <p>Name: {userData.name}</p>
      <p>Email: {userData.email}</p>
      {/* Render other user data */}
    </div>
  );
};

export default UserComponent;

SWR 的 React 代码示例

使用 SWR 可以显著简化数据请求和状态管理的代码,并提供额外的性能优势和响应式更新。

import React from 'react';
import useSWR from 'swr';
import axios from 'axios';

const fetcher = async (url) => {
  const response = await axios.get(url);
  return response.data;
};

const UserComponent = () => {
  const { data: userData, isLoading, error } = useSWR('https://api.example.com/user', fetcher);

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  if (!userData) return <div>Loading...</div>;

  return (
    <div>
      <h1>User Data</h1>
      <p>Name: {userData.name}</p>
      <p>Email: {userData.email}</p>
      {/* Render other user data */}
    </div>
  );
};

export default UserComponent;

通常,一个请求有 3 种可能的状态:“loading”、“ready”或“error”。你可以使用 data、error 和 isLoading 的值来确定当前的请求状态,并返回相应的 UI。

SWR 的优势和不同之处

  1. 自动缓存管理:SWR 自动缓存请求的数据,并在下一次请求相同数据时返回缓存数据,从而提高了应用的响应速度和性能。

  2. 本地状态自动更新:SWR 会在后台自动重新验证(revalidate)数据,当数据过期或在组件重新渲染时,会发起新的请求并更新组件的状态,保持数据的实时性。

  3. 自动错误重试:SWR 在网络错误或请求失败时,具有自动重试的能力,可以减少开发人员手动处理错误和重试逻辑的工作量。

  4. 简化代码:相比于传统的 React 数据请求和状态管理代码,使用 SWR 可以显著减少冗余代码,提高代码的可读性和维护性。

总结来说,SWR 提供了一种更加优雅和高效的方式来处理数据请求和状态管理,适用于需要即时更新和高性能数据加载的 React 应用程序。

可复用组件

在构建 web 应用时,你可能需要在 UI 的很多地方重用数据。在 SWR 上创建可重用的数据 hooks 非常容易:

function useUser(id) {
  const { data, error, isLoading } = useSWR(`/api/user/${id}`, fetcher)
 
  return {
    user: data,
    isLoading,
    isError: error,
  }
}

在组件中使用它:

function Avatar({ id }) {
  const { user, isLoading, isError } = useUser(id)
 
  if (isLoading) return <Spinner />
  if (isError) return <Error />
  return <img src={user.avatar} />
}

通过采用这种模式,你可以不必以命令的方式请求数据:开始请求、更新加载状态并返回最终结果。 相反,你的代码更具有声明性:你只需要指定组件使用什么数据即可。

真实示例

在一个真实的示例中,我们的网站显示一个导航条和内容,都取决于 user 信息:

  1. 导航栏右侧头像信息
  2. 内容欢迎语包含用户姓名信息

传统上,我们在顶级组件中使用 useEffect 请求一次数据,然后通过 props 将其传递给子组件(注意,我们现在不处理错误状态):

// 页面组件
function Page() {
  const [user, setUser] = useState(null)
 
  // 请求数据
  useEffect(() => {
    fetch("/api/user")
      .then((res) => res.json())
      .then((data) => setUser(data))
  }, [])
 
  // 全局加载状态
  if (!user) return <Spinner />
 
  return <div>
    <Navbar user={user} />
    <Content user={user} />
  </div>
}
 
// 子组件
function Navbar({ user }) {
  return <div>
    ...
    <Avatar user={user} />
  </div>
}
 
function Content({ user }) {
  return <h1>Welcome back, {user.name}</h1>
}
 
function Avatar({ user }) {
  return <img src={user.avatar} alt={user.name} />
}

通常,我们需要将所有的数据请求都保存在顶级组件中,并为树深处的每个组件添加 props。如果我们给页面添加更多的数据依赖,代码将变得更加难以维护。

虽然我们可以使用 Context(opens in a new tab) 来避免传递 props,但仍然存在动态内容问题:页面内容中的组件可以是动态的,顶级组件可能不知道其子组件将需要什么数据。

SWR 完美地解决了这个问题。使用我们刚刚创建的 useUser hook,可以将代码重构为:

function useUser(id) {
  const { data, error, isLoading } = useSWR(`/api/user/${id}`, fetcher)
 
  return {
    user: data,
    isLoading,
    isError: error,
  }
}

// 页面组件
function Page() {
  return <div>
    <Navbar />
    <Content />
  </div>
}
 
// 子组件
function Navbar() {
  return <div>
    ...
    <Avatar />
  </div>
}
 
function Content() {
  const { user, isLoading } = useUser()
  if (isLoading) return <Spinner />
  return <h1>Welcome back, {user.name}</h1>
}
 
function Avatar() {
  const { user, isLoading } = useUser()
  if (isLoading) return <Spinner />
  return <img src={user.avatar} alt={user.name} />
}

现在数据已 绑定 到需要该数据的组件上,并且所有组件都是相互 独立 的。所有的父组件都不需要关心关于数据或数据传递的任何信息。它们只是渲染。现在代码更简单,更易于维护了。最棒的是,只会有 1 个请求 发送到 API,因为它们使用相同的 SWR key,因此请求会被自动 去除重复缓存共享

而且,你的应用现在能够在 用户聚焦或网络重连 时重新请求数据!这意味着当用户的笔记本电脑从睡眠状态唤醒,或用户在切换浏览器标签页时,数据将自动刷新。

特性解读

自动重新请求

https://swr.vercel.app/zh-CN/docs/revalidation

1. 聚焦时重新请求

当你重新聚焦一个页面或在标签页之间切换时,SWR 会自动重新请求数据。这个功能非常实用,可以保持网站同步到最新数据。对于在长时间位于后台的标签页,或 休眠 的电脑等情况下刷新数据也很有帮助。

在传统实现中,具体原理是什么?

在 React 中,针对在长时间处于后台标签页或电脑休眠的情况下刷新数据,可以利用以下方法来监听页面可见性变化并触发数据刷新:使用 Page Visibility API。

Page Visibility API 提供了一种检测页面可见性的标准方法,可以通过监听 visibilitychange 事件来处理页面的可见性变化。具体步骤如下:

  1. 添加事件监听器:在组件的生命周期中添加 visibilitychange 事件监听器。

  2. 检查页面状态:在事件处理函数中检查页面的 document.visibilityState 属性,以确定页面当前的可见性状态。

  3. 触发数据刷新:根据页面的可见性状态来触发数据刷新或其他需要的操作。

示例代码如下:

import React, { useEffect } from 'react';

const DataRefreshingComponent = () => {
  useEffect(() => {
    const handleVisibilityChange = () => {
      if (document.visibilityState === 'visible') {
        // 页面变为可见时,执行数据刷新操作
        console.log('Page is visible, refreshing data...');
        fetchData(); // 例如,调用刷新数据的函数
      }
    };

    document.addEventListener('visibilitychange', handleVisibilityChange);

    return () => {
      document.removeEventListener('visibilitychange', handleVisibilityChange);
    };
  }, []);

  const fetchData = async () => {
    // 例如,通过 Axios 或 Fetch API 获取数据的逻辑
    try {
      const response = await fetch('https://api.example.com/data');
      const data = await response.json();
      console.log('Fetched data:', data);
      // 更新组件中的数据状态或执行其他操作
    } catch (error) {
      console.error('Error fetching data:', error);
    }
  };

  return (
    <div>
      <h1>Data Refreshing Component</h1>
      {/* 显示数据等其他UI */}
    </div>
  );
};

export default DataRefreshingComponent;

解释:

  • useEffect 钩子:使用 useEffect 钩子来在组件挂载时添加事件监听器,并在组件卸载时移除事件监听器,确保页面可见性变化时能正确触发相应的处理函数。

  • handleVisibilityChange 函数:处理 visibilitychange 事件的回调函数,根据 document.visibilityState 的值来判断页面当前是否可见,并在页面变为可见时执行数据刷新操作。

  • fetchData 函数:示例中的数据获取函数,通过 Fetch API 或 Axios 发起网络请求,获取最新数据并更新组件状态或执行其他逻辑。

通过以上方法,你可以在 React 应用中监听页面的可见性变化,并在页面重新变为可见时执行需要的数据刷新操作,从而保持应用的数据更新和实时性。

2. 定期重新请求

在很多情况下,数据会因为多个设备、多个用户、多个选项卡而发生改变。那么我们如何随着时间的推移更新屏幕上的数据呢?SWR 会为你提供自动重新请求数据的选项。这很 智能,意味着只有与 hook 相关的组件 在屏幕上 时,才会重新请求。

你可以通过设置 refreshInterval 值来启用它:

useSWR('/api/todos', fetcher, { refreshInterval: 1000 })

还有其他选项,例如 refreshWhenHidden 和 refreshWhenOffline。这两项默认都是禁用的,所以当网页不在屏幕上或没有网络连接时,SWR 不会请求。

在传统实现中,具体原理是什么?

在传统的 React 应用中,实现类似于 SWR 的智能数据刷新和缓存管理可以通过以下方式来处理:

  1. 定时器和定时刷新

一种简单的方法是使用 JavaScript 的 setIntervalsetTimeout 函数来定时触发数据请求并更新组件状态。

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const DataRefreshingComponent = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await axios.get('https://api.example.com/data');
        setData(response.data);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };

    fetchData(); // 初始加载数据

    const interval = setInterval(() => {
      fetchData(); // 每隔一段时间重新请求数据
    }, 60000); // 例如每分钟刷新一次

    return () => {
      clearInterval(interval); // 清除定时器
    };
  }, []);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  if (!data) return null;

  return (
    <div>
      <h1>Data Refreshing Component</h1>
      <p>Data: {data}</p>
      {/* 显示其他数据或UI */}
    </div>
  );
};

export default DataRefreshingComponent;
  1. 使用 WebSocket 实时更新

另一种方法是使用 WebSocket 技术,在数据发生变化时实时推送更新到客户端。这需要在服务端和客户端都实现 WebSocket 的支持。

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const DataRefreshingComponent = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await axios.get('https://api.example.com/data');
        setData(response.data);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };

    fetchData(); // 初始加载数据

    const socket = new WebSocket('wss://api.example.com/socket');

    socket.onmessage = (event) => {
      const newData = JSON.parse(event.data);
      setData(newData); // 收到 WebSocket 数据更新时更新状态
    };

    return () => {
      socket.close(); // 关闭 WebSocket 连接
    };
  }, []);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  if (!data) return null;

  return (
    <div>
      <h1>Data Refreshing Component</h1>
      <p>Data: {data}</p>
      {/* 显示其他数据或UI */}
    </div>
  );
};

export default DataRefreshingComponent;
  1. 使用第三方库实现类似的功能

除了自行实现定时器或 WebSocket 外,也可以使用像 react-use 这样的第三方库,它提供了一些常见的 React 自定义钩子,包括定时器和周期性数据更新的钩子,可以帮助简化实现过程。

import React from 'react';
import useInterval from 'react-use/lib/useInterval';
import axios from 'axios';

const DataRefreshingComponent = () => {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);

  useInterval(async () => {
    try {
      setLoading(true);
      const response = await axios.get('https://api.example.com/data');
      setData(response.data);
      setLoading(false);
    } catch (error) {
      setError(error);
      setLoading(false);
    }
  }, 60000); // 每分钟刷新一次

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  if (!data) return null;

  return (
    <div>
      <h1>Data Refreshing Component</h1>
      <p>Data: {data}</p>
      {/* 显示其他数据或UI */}
    </div>
  );
};

export default DataRefreshingComponent;

以上是一些在传统的 React 应用中实现定时刷新和实时更新数据的方法。这些方法可以根据具体的需求和场景来选择,保证应用中的数据随着时间的推移自动更新,以便于多设备、多用户、多选项卡之间的数据同步和实时性。

3. 重新连接时重新请求

当用户重新联机时重新请求非常有用。这种情况经常发生在用户解锁了他们的计算机但网络还没有连上时。为了确保数据始终是最新的,SWR 会在网络恢复时自动重新请求。

在传统实现中,具体原理是什么?

在传统的 React 应用中,要实现在网络恢复时自动重新请求数据,可以借助浏览器的在线与离线事件(Online and Offline Events)来监听网络连接状态的变化,并在网络重新连接时手动触发数据请求。虽然没有像 SWR 那样的自动重新请求机制,但可以通过以下步骤来实现类似的功能:

使用浏览器在线与离线事件

浏览器提供了 onlineoffline 事件,可以监听到网络的连接状态变化。当用户解锁计算机并且网络连接恢复时,会触发 online 事件,我们可以在这时候手动重新请求数据。

示例代码如下:

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const DataRefreshingComponent = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await axios.get('https://api.example.com/data');
        setData(response.data);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };

    fetchData(); // 初始加载数据

    const handleOnlineStatusChange = () => {
      if (navigator.onLine) {
        fetchData(); // 网络恢复时重新请求数据
      }
    };

    window.addEventListener('online', handleOnlineStatusChange);

    return () => {
      window.removeEventListener('online', handleOnlineStatusChange);
    };
  }, []);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  if (!data) return null;

  return (
    <div>
      <h1>Data Refreshing Component</h1>
      <p>Data: {data}</p>
      {/* 显示其他数据或UI */}
    </div>
  );
};

export default DataRefreshingComponent;

解释:

  • useEffect 钩子:使用 useEffect 钩子来在组件挂载时添加事件监听器,并在组件卸载时移除事件监听器。

  • fetchData 函数:数据请求的逻辑,通过 Axios 或 Fetch API 发起网络请求,获取最新数据并更新组件状态。

  • handleOnlineStatusChange 函数:处理 online 事件的回调函数,当网络恢复时手动调用 fetchData 函数重新请求数据。

  • window.addEventListener('online', ...):监听 online 事件,即网络连接恢复时触发。

通过以上方式,可以在用户解锁计算机并网络连接恢复时,手动触发数据请求,以确保数据始终是最新的。这种方法虽然需要手动处理,但可以有效地处理用户在网络不稳定或断开连接后重新连接的情况。

条件数据请求

https://swr.vercel.app/zh-CN/docs/conditional-fetching

1. 按需请求

使用 null 或传一个函数作为 key 来有条件地请求数据。如果函数抛出错误或返回 falsy 值,SWR 将不会启动请求。

// 有条件的请求
const { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)
 
// ...或返回一个 falsy 值
const { data } = useSWR(() => shouldFetch ? '/api/data' : null, fetcher)
 
// ... 或在 user.id 未定义时抛出错误
const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)

2. 依赖请求

SWR 还允许请求依赖于其他数据的数据。当需要一段动态数据才能进行下一次数据请求时,它可以确保最大程度的并行性(avoiding waterfalls)以及串行请求。

function MyProjects () {
  const { data: user } = useSWR('/api/user')
  const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)
  // 传递函数时,SWR 会用返回值作为 `key`。
  // 如果函数抛出错误或返回 falsy 值,SWR 会知道某些依赖还没准备好。
  // 这种情况下,当 `user`未加载时,`user.id` 抛出错误
 
  if (!projects) return 'loading...'
  return 'You have ' + projects.length + ' projects'
}

数据更改

https://swr.vercel.app/zh-CN/docs/mutation

SWR 提供了 mutateuseSWRMutation 两个 API 用于更改远程数据及相关缓存。

这里主要学习几个概念:

1. 乐观更新

多情况下,应用本地的数据更改是一个让人感觉快速的好方法——不需要等待远程数据源。比如我们明确知道 edit 某个 item 的数据,并且发起了 post 修改请求,可以先应用本地的 itemNew,等待接口返回再进一步处理。

使用 optimisticData 选项,你可以手动更新你的本地数据,同时等待远程数据更改的完成。搭配 rollbackOnError 使用,你还可以控制何时回滚数据。

import useSWR, { useSWRConfig } from 'swr'
 
function Profile () {
  const { mutate } = useSWRConfig()
  const { data } = useSWR('/api/user', fetcher)
 
  return (
    <div>
      <h1>My name is {data.name}.</h1>
      <button onClick={async () => {
        const newName = data.name.toUpperCase()
        const user = { ...data, name: newName }
        const options = {
          optimisticData: user,
          rollbackOnError(error) {
            // 如果超时中止请求的错误,不执行回滚
            return error.name !== 'AbortError'
          },
        }
 
        // 立即更新本地数据
        // 发送一个请求以更新数据
        // 触发重新验证(重新请求)确保本地数据正确
        mutate('/api/user', updateFn(user), options);
      }}>Uppercase my name!</button>
    </div>
  )
}

当你设置了optimisticData 选项时,有可能在乐观数据展示给用户后,远程数据更改却失败了。在这种情况下,你可以启用 rollbackOnError,将本地缓存恢复到之前的状态,确保用户看到的是正确的数据。

2. 在数据更改后更新缓存

这是指,有时远程数据更改的请求会直接返回更新后的数据,因此不需要发送额外的请求来加载它。比如一个列表里的某一项更新接口会返回新的 item 的数据,我们可以利用该数据将其更新到本地对应的 item 缓存里,也就不需要获取列表数据了。 你可以启用 populateCache 选项,用数据更改的响应来更新 useSWR 的缓存。

const updateTodo = () => fetch('/api/todos/1', {
  method: 'PATCH',
  body: JSON.stringify({ completed: true })
})
 
mutate('/api/todos', updateTodo, {
  populateCache: (updatedTodo, todos) => {
   // 过滤列表并返回更新后的待办项
    const filteredTodos = todos.filter(todo => todo.id !== '1')
    return [...filteredTodos, updatedTodo]
  },
 
  // 因为 API 已经给了我们更新后的数据,所以我们不需要重新请求验证它。
  revalidate: false
})

3. 基于当前数据进行数据更改

有时你想根据当前的数据来更新部分数据。通过 mutate,你可以传入一个接收当前缓存值的异步函数,如果有的话,并返回一个更新的文档。

mutate('/api/todos', async todos => {
  // 让我们将 ID 为 `1` 的待办事项更新为已完成
  const updatedTodo = await fetch('/api/todos/1', {
    method: 'PATCH',
    body: JSON.stringify({ completed: true })
  })
 
  // 过滤列表并返回更新后的待办项
  const filteredTodos = todos.filter(todo => todo.id !== '1')
  return [...filteredTodos, updatedTodo]
  // 因为 API 已经给了我们更新后的信息,所以我们不需要去重新验证它。
}, { revalidate: false })

4. 更改多项数据

https://swr.vercel.app/zh-CN/docs/mutation#mutate-multiple-items

5. 避免竞态条件

mutateuseSWRMutation 都可以避免 useSWR 之间的竞态条件。

在软件开发中,竞态条件(Race Condition)是指多个并发操作试图在同一时间段内对共享资源进行读写,但它们的执行顺序或时间顺序是不确定的,从而导致最终结果可能依赖于操作的执行顺序而产生不确定性或错误。

具体到 React 应用中使用 SWR(stale-while-revalidate)时,竞态条件通常指的是多个组件同时尝试访问和更新同一份数据源(比如一个 API 的数据)。以下是一些常见的竞态条件场景:

  1. 并行请求

    • 多个组件同时请求相同的数据源,并且这些请求没有进行合理的同步或控制,可能导致多次不必要的网络请求或数据加载。
  2. 数据更新

    • 多个组件同时试图更新同一份数据源,而没有合适的同步机制。这可能导致数据的不一致性或最终状态与预期不符。
  3. 缓存与数据同步

    • 当组件在使用缓存数据时,同时又有其他组件在后台更新了同一份数据源,没有良好的同步机制会导致显示的数据不及时更新或显示过时的信息。

在 React 应用中,SWR 的 mutate 方法和 useSWRMutation 钩子的设计就是为了帮助开发者避免这些竞态条件问题。它们提供了一种机制来确保数据的一致性和更新时的同步性:

  • mutate 方法:允许开发者手动更新缓存数据,并确保在更新后,相关的组件可以立即获取到最新的数据,而不需要等待 SWR 的自动重新验证或失效。

  • useSWRMutation 钩子:用于发起数据更新请求,并在请求完成后自动使相关数据失效,以便后续的请求可以获取到更新后的数据。它们的设计目的是通过管理数据的更新过程,来避免多个请求或更新操作之间的竞态条件问题。

总结来说,竞态条件是指在并发环境中多个操作对共享资源进行读写时可能出现的不确定性或错误,而 SWR 的 mutateuseSWRMutation 提供了机制来帮助开发者在 React 应用中管理和避免这类问题的发生,确保数据的一致性和正确性。

具体示例:

function Profile() {
  const { data } = useSWR('/api/user', getUser, { revalidateInterval: 3000 })
  const { trigger } = useSWRMutation('/api/user', updateUser)
 
  return <>
    {data ? data.username : null}
    <button onClick={() => trigger()}>Update User</button>
  </>
}

正常情况下 useSWR hook 可能会因为聚焦,轮询或者其他条件在任何时间刷新,这使得展示的 username 尽可能是最新的。然而,由于我们在 useSWR 的刷新过程中几乎同时发生了一个数据更改,可能会出现 getUser 请求更早开始,但是花的时间比 updateUser 更长,导致竞态情况。

幸运的是 useSWRMutation 可以为你自动处理这种情况。在数据更改后,它会告诉 useSWR 放弃正在进行的请求和重新验证,所以旧的数据永远不会被显示。

订阅

https://swr.vercel.app/zh-CN/docs/subscription

预请求

https://swr.vercel.app/zh-CN/docs/prefetching

我们知道对于预请求,可以使用 preload,有关 preoload 可以阅读 WHAT - script 加载(含 async、defer、preload 和 prefetch 区别) 。

preload 适用于顶级页面数据的请求:

<link rel="preload" href="/api/data" as="fetch" crossorigin="anonymous">

它将在 HTML 加载时预请求数据,甚至是在 JavaScript 开始下载之前。

SWR provides the preload API to prefetch the resources programmatically and store the results in the cache. preload accepts key and fetcher as the arguments.

You can call preload even outside of React.

import { useState } from 'react'
import useSWR, { preload } from 'swr'
 
const fetcher = (url) => fetch(url).then((res) => res.json())
 
// Preload the resource before rendering the User component below,
// this prevents potential waterfalls in your application.
// You can also start preloading when hovering the button or link, too.
preload('/api/user', fetcher)
 
function User() {
  const { data } = useSWR('/api/user', fetcher)
  ...
}
 
export default function App() {
  const [show, setShow] = useState(false)
  return (
    <div>
      <button onClick={() => setShow(true)}>Show User</button>
      {show ? <User /> : null}
    </div>
  )
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/774428.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CASS7.0按方向和距离绘制图形

1、绘制工具 2、按方向和距离绘制 &#xff08;1&#xff09;切换方向 &#xff08;2&#xff09;距离输入

【算法:贪心】:贪心算法介绍+基础题(四个步骤);柠檬水找零(交换论证法)

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;C课程学习 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 前言&#xff1a; 暑假马上就要留校学习算法了&#xff0c;现在先学习一下基本的算法打打基础。本篇要讲的是…

数据库数据修改和删除操作详解

目录 &#x1f383;摘要 1. 数据库数据修改概述 2. 数据更新操作 2.1MySQL数据更新示例 3. 数据删除概述 4.使用DELETE进行数据删除 4.1 DELETE的基本语法 4.2 DELETE的使用场景 4.3 DELETE示例 5. 使用TRUNCATE进行数据删除 5.1 TRUNCATE的基本语法 5.2 TRUNCATE的…

Vue3:全局播放背景音乐

说明&#xff1a;一个全局播放的背景音乐&#xff0c;首页无音乐无音乐图标&#xff0c;在首页互动跳转页面并开始播放音乐&#xff0c;切换页面不需暂停音乐也不会重置音乐&#xff0c;可以通过音乐图标控制暂停或播放。 MusicPlay.vue&#xff08;音乐组件&#xff09; <…

新手高效指南:电子元器件BOM表创建/制作及配单全教程

在科技日新月异的今天&#xff0c;电子产品设计与制造不仅是创新精神的展现&#xff0c;更是对精确度与效率的不懈追求。在这个过程中&#xff0c;一份精细且全面的BOM&#xff08;物料清单&#xff09;犹如一座桥梁&#xff0c;连接着创意与现实世界。BOM不仅细致记录了产品所…

Facebook群发消息API接口的申请流程详解!

Facebook 群发消息api接口如何集成&#xff1f;怎么使用API接口&#xff1f; 在现代社交媒体营销中&#xff0c;群发消息是与客户保持互动的重要工具。Facebook群发消息API接口提供了一种有效的方法来实现这一目标。本文将详细介绍如何申请Facebook群发消息API接口的具体步骤和…

【qt】如何获取本机的IP地址?

需要用到这个类QHostInfo和pro里面添加network模块 用这个类的静态函数forName()来获取该主机名的信息 返回的就是这个类 这个QHostInfo类就包括主机的IP地址信息 用静态函数addresses()来获取 返回的是一个QHostAddress的容器 QList<QHostAddress>addrList hostIn…

深入分析 Android BroadcastReceiver (九)

文章目录 深入分析 Android BroadcastReceiver (九)1. Android 广播机制的扩展应用与高级优化1.1 广播机制的扩展应用1.1.1 示例&#xff1a;有序广播1.1.2 示例&#xff1a;粘性广播1.1.3 示例&#xff1a;局部广播 1.2 广播机制的高级优化1.2.1 示例&#xff1a;使用 Pending…

Gemini for China 大更新,现已上架 Android APP!

官网&#xff1a;https://gemini.fostmar.online/ Android APP&#xff1a;https://gemini.fostmar.online/gemini_1.0.apk 一、Android APP 如果是 Android 设备&#xff0c;则会直接识别到并给下载链接。PC 直接对话即可。 二、聊天记录 现在 Gemini for China&#xff…

mysql8 导入导出工具类,支持windows 和linux

概述 1&#xff09;导入导出工具类 支持windows 和linux&#xff0c;详见第3部分 2&#xff09;导入、导出参数在 dbeaver 中应用&#xff0c;详见第4部分 整理原因: 1&#xff09;中文乱码 --default-character-setutf8 2&#xff09;BLOB 导出后&#xff0c;导入失败 --he…

DatawhaleAI夏令营2024 Task2

#AI夏令营 #Datawhale #夏令营 赛题解析一、Baseline详解1.1 环境配置1.2 数据处理任务理解2.3 prompt设计2.4 数据抽取 二、完整代码总结 赛题解析 赛事背景 在数字化时代&#xff0c;企业积累了大量对话数据&#xff0c;这些数据不仅是交流记录&#xff0c;还隐藏着宝贵的信…

8.13 矢量图层面要素反转面要素渲染(Inverted polygons Renderer)

前言 本章介绍矢量图层面要素反转面要素(Inverted polygons Renderer)的使用说明&#xff1a;文章中的示例代码均来自开源项目qgis_cpp_api_apps 反转面要素(Inverted polygons Renderer) 反转面要素渲染常用于掩膜数据。 反转面要素(Inverted polygons Renderer)是一种渲染方…

软件测试之接口自动化测试实战(完整版)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 自从看到阿里云性能测试 PTS 接口测试开启免费公测&#xff0c;就想着跟大家分享交流一下如何实现…

使用笔记之-E语言微信支付支付宝支付源代码

首先下载E语言微信支付&支付宝支付源代码 http://www.htsoft.com.cn/download/E_WeiXin_ZhiFuBao_ZhiFu.rar

编译开源车载Linux操作系统AGL

随着汽车行业的智能化和互联化趋势日益明显&#xff0c;车载系统作为汽车的重要组成部分&#xff0c;其性能和功能也受到了越来越多的关注。Linux作为一款开源的操作系统&#xff0c;具有稳定性高、安全性强、可定制性好等优点&#xff0c;因此成为了车载系统领域的热门选择。 …

黄小米-从田间到餐桌的美味之旅

甘肃黄小米颗粒饱满&#xff0c;色泽金黄&#xff0c;富含多种营养成分&#xff0c;如蛋白质、膳食纤维、维生素和矿物质等。其口感香糯&#xff0c;煮粥时香气扑鼻&#xff0c;米油丰富&#xff0c;味道醇厚。由于甘肃地区独特的地理和气候条件&#xff0c;包括充足的日照、较…

SQL 与 NoSQL 数据库:一场关于灵活性与结构的对话

文章目录 引言SQL 数据库&#xff1a;传统之光定义特征优势缺点 NoSQL 数据库&#xff1a;新时代的弹性定义特征优势缺点 何时选择 NoSQL&#xff1f;场景1&#xff1a;海量数据与高并发场景2&#xff1a;灵活性需求场景3&#xff1a;实时数据分析场景4&#xff1a;分布式系统 …

ZW3D二次开发_CAM_设置参数并输出NC文件

ZW3D可以输出NC文件&#xff0c;代码示例如下&#xff1a; int index;int ret cvxCmInqIndexFromName(CM_OUT, (char*)"NC", &index);//获取参数svxNcSetting ncSet;ret cvxCmGetOutputNCSet(index, &ncSet);//设置参数strcpy_s(ncSet.filename, "C:\…

【上海38℃】酷热之下,AI能否给我降降温?

近日上海的高温冲上热搜&#xff0c;要我就早早躲进机房&#xff0c;聆听嘈杂的轰鸣&#xff0c;穿着皮夹克喝着热可可&#xff0c;看着log——以上都是我的白日梦&#xff0c;哈哈哈^ ^) 不过&#xff0c;服务器和工作站确实“真芯热”&#xff0c;尤其是在高负载下&#xff…

【深度学习】图形模型基础(5):线性回归模型第二部分:单变量线性回归模型

1.引言 在统计学与机器学习的广阔领域中&#xff0c;线性回归作为一种基础而强大的预测技术&#xff0c;其核心在于通过输入变量&#xff08;或称预测器、自变量&#xff09;来估计输出变量&#xff08;响应变量、因变量&#xff09;的连续值。本章聚焦于线性回归的一个基本但…