devStandard/docs/learning/7-react/9-react-query.md
2025-03-29 14:35:49 +08:00

5.0 KiB
Executable File

react-query

适用于 React Hooks 的请求库 远程数据的状态管理(也包括数据获取)

传统状态管理的缺点:

  1. 远程数据无法控制
  2. 需要写很多重复代码
  3. 共享数据可能被修改
  4. 数据可能过时

react-query的优点:

  1. 缓存控制
  2. 可以合并请求
  3. 在后台更新过时数据
  4. 知道数据什么时候过时
  5. 分页和延迟加载等性能优化
  6. 数据更新触发视图更新
  7. 更好的内存回收
  8. 存储更结构化并共享

文档

  1. 官方文档: https://tanstack.com/query/latest/docs/react/overview
  2. 中文翻译: https://cangsdarm.github.io/react-query-web-i18n/react/
  3. 中文教程: https://juejin.cn/post/6937833844837974053 https://segmentfault.com/a/1190000041939135

安装

pnpm add @tanstack/react-query

兼容性:

Chrome >= 73
Firefox >= 78
Edge >= 79
Safari >= 12.0
iOS >= 12.0
opera >= 53

使用

三个重要概念: 查询, 修改, 主动查询失效

查询

  1. 实例化 queryClient
  2. 用 QueryClientProvider 包裹 app
// main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'

import {
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query'

const queryClient = new QueryClient()

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  </React.StrictMode>
)
  1. 用 useQuery 获取 异步数据
/**
   * useQuery
   *  - queryKey: 查询键, 是个数组, 通过不同的查询键来标识不同接口返回的不同数据, 简单理解成localstorage里的key
   *      - key内的元素可以是嵌套数组、对象、字符串、数字 ['zen', { form: 'confucius' }]
   *      - 从通用到特殊, 为了避免重复, 第一个可以是个字符串
   *      - 当key发生变化时, 会自动发起新的请求, 并缓存在新的key中
   *  - queryFn: 查询函数, 不只axios, fetch, 所有Promise都可以
   *      - 默认传参 {meta, pageParam, queryKey, signal}
   *  - 返回:
   *      - 状态只会是三种中的一种
   *          - isLoading: 加载状态
   *          - isError: 查询遇到一个错误
   *          - isSuccess: 查询成功,并且数据可用
   *      - data: 成功时的数据
   *      - error: 失败时的错误信息
   */
import axios from 'axios'
import { useQuery} from '@tanstack/react-query'

type Props = {}

const StusList = (props: Props) => {

  const getStudentsList = async (key:unknown)=>{
    console.log('key:', key)
    try {
      const res = await axios.get('${window.apiUrl}/students')
    return res.data
    } catch (error) {
      if(error instanceof Error){
        return error.message
      }
    }
  }
  const { isLoading, isError, data, error } = useQuery(['studentsList'], getStudentsList)

  return (
    <>
      {isLoading && <span>数据正在加载中...</span>}
      {data && <span>{JSON.stringify(data)}</span>}
      {isError && error instanceof Error && <span>{error.message}</span>}
      {/*  error 默认类型为unknown, 运行时进行检查 */}
    </>
  )
}

export default StusList

并行查询

import axios from 'axios'
import { useState } from 'react'
import { useQuery } from '@tanstack/react-query'

const ParallelRequest = () => {
  const user1Query = useQuery(['stuInfo', 1], () => {
    return axios.get(`${window.apiUrl}/students/1`).then(res => res.data)
  })
  const user2Query = useQuery(['stuInfo', 2], () => {
    return axios.get(`${window.apiUrl}/students/2`).then(res => res.data)
  })

  const query = useQuery(['stuInfo', '1&2'], () => {
    return Promise.all([
      axios.get(`${window.apiUrl}/students/1`).then(res => res.data),
      axios.get(`${window.apiUrl}/students/2`).then(res => res.data),
    ])
  })

  return (
    <div>
      先完成先展示:
      {user1Query.isLoading && <p>用户1正在加载中...</p>}
      {user1Query.isError && <p>用户1数据获取错误!</p>}
      {user1Query.data && <p>用户1数据:{JSON.stringify(user1Query.data)}</p>}
      {user2Query.isLoading && <p>用户2正在加载中...</p>}
      {user2Query.isError && <p>用户2数据获取错误!</p>}
      {user2Query.data && <p>用户2数据:{JSON.stringify(user2Query.data)}</p>}
      <br />
      全部完成再展示:
      {query.isLoading && <p>正在加载中...</p>}
      {query.isError && <p>请求错误!</p>}
      {query.data && <p>{JSON.stringify(query.data)}</p>}
    </div>
  )
}

export default ParallelRequest

第一部分 用户1, 用户2的数据, 谁先完成获取就展示谁

第二部分, 用户1 用户2全部获取完成后, 再进行展示, 在查询函数中使用了Promise.all

动态并行查询

查询数量在每次渲染时会发生变化, 不能使用手动查询, 使用useQueries

举例: 第一次查询react, vue 两个项目的仓库, 第二次查询 selvte, ## Angular 一个项目的仓库

修改

使查询失效