最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • React-Query 让你的状态管理更优雅

    正文概述 掘金(wxy201008)   2021-03-10   1526

    React-Query 让你的状态管理更优雅

    下面就是一个简单的从服务端获取数据的案例

    function App() {
    
      const [data, updateData] = useState(null);
      const [isError, setError] = useState(false);
      const [isLoading, setLoading] = useState(false);
      
      useEffect(async () => {
        setError(false);
        setLoading(true);
        try {
          const data = await axios.get('/api/user');
          updateData(data);
        } catch(e) {
          setError(true);
        }
        setLoading(false);
      }, [])
    
    }
    

    在使用 React Hooks 编写组件时,我们常需要手动维护来自服务器的处理状态。在日常开发中引起一些麻烦。 处理异步数据时,我们需要考虑很多事情,例如更新,缓存或重新获取。 使用 React-Query 能够更高效的帮你管理服务端的状态。

    React-Query 是什么

    React-Query 让你的状态管理更优雅

    这是一个适用于 React Hooks 的请求库。 这个库将帮助你获取、同步、更新和缓存你的远程数据, 提供两个简单的 hooks,就能完成增删改查等操作React-Query 使用声明式管理服务端状态,可以使用零配置开箱即用地处理缓存,后台更新和陈旧数据。无需繁琐的配置,编写useReduce,以及维护全局状态,只要知道如何使用 Promise 或 async / await ,传递一个可解析数据(或引发错误)的函数,剩下的交给 React-Query 就好了,使用更少的代码获得更高的效率.

    开始使用 React-Query

    安装 React-Query

     $ npm i react-query
     # or
     $ yarn add react-query
    

    下面我们用 React-Query改写

    
     import { useQuery } from 'react-query'
     
     function App() {
    
       const {data, isLoading, isError} = useQuery('userData', () => axios.get('/api/user'));
       
       if (isLoading) {
         return <div>loading</div>;
       }
       
       return (
         <ul>
           {data.map(user => <li key={user.id}>{user.name}</li>)}
         </ul>
       )
     }
    
    

    例子中 "userData" 字符串就是这个 query 独一无二的key。 可以看到,React-Query封装了完整的请求中间状态(isLoading、isError...)。 不仅如此,React-Query还为我们做了如下工作:

    1. 多个组件请求同一个query时只发出一个请求
    2. 缓存数据失效/更新策略(判断缓存合适失效,失效后自动请求数据)
    3. 对失效数据垃圾清理

    React-Query 中的三个重要知识点

    常用参数配置

    • staleTime 重新获取数据的时间间隔 默认0
    • cacheTime 数据缓存时间 默认 1000 60 5 5分钟
    • retry 失败重试次数 默认 3次
    • refetchOnWindowFocus 窗口重新获得焦点时重新获取数据 默认 false
    • refetchOnReconnect 网络重新链接
    • refetchOnMount 实例重新挂载
    • enabled 如果为“false”的化,“useQuery”不会触发,需要使用其返回的“refetch”来触发操作

    如何全局配置呢?如下:

    import { ReactQueryConfigProvider, ReactQueryProviderConfig } from 'react-query';
    
    const queryConfig: ReactQueryProviderConfig = {
      /**
       * refetchOnWindowFocus 窗口获得焦点时重新获取数据
       * staleTime 过多久重新获取服务端数据
       * cacheTime 数据缓存时间 默认是 5 * 60 * 1000 5分钟
       */
      queries: { 
        refetchOnWindowFocus: true,
        staleTime: 5 * 60 * 1000, 
        retry: 0
      },
    };
    
    ReactDOM.render(
        <ReactQueryConfigProvider config={queryConfig}>
            <App />
        </ReactQueryConfigProvider>
        document.getElementById('root')
      );
    也可以单独配置,如下:
    
    function Todos() {
       // 第三个参数即可传参了
       // "enabled"参数为false的化,不会自动发起请求,而是需要调用“refetch”来触发
       const {
         isIdle,
         isLoading,
         isError,
         data,
         error,
         refetch,
         isFetching,
       } = useQuery('todos', fetchTodoList, {
         enabled: false,
       })
     
       return (
         <>
           <button onClick={() => refetch()}>Fetch Todos</button>
     
           {isIdle ? (
             'Not ready...'
           ) : isLoading ? (
             <span>Loading...</span>
           ) : isError ? (
             <span>Error: {error.message}</span>
           ) : (
             <>
               <ul>
                 {data.map(todo => (
                   <li key={todo.id}>{todo.title}</li>
                 ))}
               </ul>
               <div>{isFetching ? 'Fetching...' : null}</div>
             </>
           )}
         </>
       )
     }
    

    数据查询与操作

    useQuery(查)查询数据 (Get)

    基本使用方法

    function Todos() {
       // useQuery的第一个参数,作为useQuery查询的唯一标识,该值唯一
       // 可以是string、array、object
       // string -> useQuery('todos', ...) queryKey === ['todos']
       // array -> useQuery(['todo', 5], ...) queryKey === ['todo', 5]
       // object -> useQuery(['todo', 5, { preview: true }], ...)  queryKey === ['todo', 5, { preview: true }]
       const { isLoading, isError, data, error } = useQuery('todos', fetchTodoList)
    
       if (isLoading) {
         return <span>Loading...</span>
       }
    
       if (isError) {
         return <span>Error: {error.message}</span>
       }
    
       // also status === 'success', but "else" logic works, too
       return (
         <ul>
           {data.map(todo => (
             <li key={todo.id}>{todo.title}</li>
           ))}
         </ul>
       )
     }
    

    传递参数

    function Todos({ completed }) {
        // useQuery(['todo', { status: 1, page: 1 }], ...)  queryKey === ['todo', { status: 1, page: 1 }]
        // 传递参数给“fetchTodoList”使用
       const queryInfo = useQuery(['todos', { status: 1, page: 1 }], fetchTodoList)
     }
    
     // 函数参数
     // key -> “todos”
     // status -> 1 page -> 1
     function fetchTodoList(key, { status, page }) {
       return new Promise()
       // ...
     }
    

    该库还实现了常用的查询操作:

    • 分页查询
    • 无限滚动

    useMutation(增、改、删)操作数据 (Post,Delete,Patch,Put

    // 当“mutate()”被调用时,执行“pingMutation”
    const PingPong = () => {
       const [mutate, { status, data, error }] = useMutation(pingMutation)
    
       const onPing = async () => {
         try {
           const data = await mutate()
           console.log(data)
         } catch {
         }
       }
       return <button onClick={onPing}>Ping</button>
     }
    

    传递参数

    // "mutate({title})"就会将参数“title”传递给“createTodo”函数了
    const createTodo = ({ title }) => {
      console.log("title ", title)
    }
    
    const CreateTodo = () => {
    const [title, setTitle] = useState('')
    const [mutate] = useMutation(createTodo)
    
    const onCreateTodo = async e => {
        e.preventDefault()
    
        try {
        await mutate({ title })
        // Todo was successfully created
        } catch (error) {
        // Uh oh, something went wrong
        }
    }
    
    return (
        <form onSubmit={onCreateTodo}>
        <input
            type="text"
            value={title}
            onChange={e => setTitle(e.target.value)}
        />
        <br />
        <button type="submit">Create Todo</button>
        </form>
    )
    }
    

    清除缓存

    每当我们编辑完一篇文章,返回列表页面,如果不清除缓存,那么数据还是缓存的数据,所以需要清除缓存,使得“userQuery”失效,回到列表页的时候重新拉取最新数据

    参考代码如下

    import { useMutation, useQueryCache } from 'react-query'
    
    const queryCache = useQueryCache()
    
    const [mutate] = useMutation(addTodo, {
        onSuccess: () => {
            // invalidateQueries 的匹配规则
            // eg:
            // queryCache.invalidateQueries('todos') 那么如下两个`query key`都会被匹配到,匹配到的缓存都会失效
            // const todoListQuery = useQuery('todos', fetchTodoList)
            // const todoListQuery = useQuery(['todos', { page: 1 }], fetchTodoList)
            queryCache.invalidateQueries('todos')
            queryCache.invalidateQueries('reminders')
        },
    })
    

    Devtools 配套开发工具

    导入开发工具

    import { ReactQueryDevtools } from 'react-query/devtools'
    

    默认情况下,当process.env.NODE ENV === 'production' 时开启 Devtools ,不必担心构建时需要排除他们

    浮动模式下开启,会将devtools作为固定的浮动元素安装在开发的应用程序中,并在屏幕一角提供一个切换按钮以显示和隐藏devtools。

     import { ReactQueryDevtools } from 'react-query/devtools'
     
     function App() {
       return (
         <QueryClientProvider client={queryClient}>
           {/* The rest of your application */}
           <ReactQueryDevtools initialIsOpen={false} />
         </QueryClientProvider>
       )
     }
    
    

    React-Query 周边生态

    React-Query 周边生态满足日常开发需求,支持 TypeScript ,GraphQL 。并可在 React Native 中使用,同时也兼容服务端渲染方案 SSR 支持 Next.js 的使用

    其他方案对比

    官网相关方案对比表格

    React QuerySWR (Website)Apollo Client (Website)RTK-Query (Website)
    Github Repo / Stars18K16K16K372Platform RequirementsReactReactReact, GraphQLReduxTheir Comparison(none)(none)ComparisonSupported Query SyntaxPromise, REST, GraphQLPromise, REST, GraphQLGraphQLPromise, REST, GraphQLSupported FrameworksReactReactReact + OthersAnySupported Query KeysJSONJSONGraphQL QueryJSONQuery Key Change DetectionDeep Compare (Stable Serialization)Referential Equality (===)Deep Compare (Unstable Serialization)Referential Equality (===)Query Data Memoization LevelQuery + Structural SharingQueryQuery + Entity + Structural SharingQueryBundle Size11.2KB5.0KB33.9KB10.3KBAPI DefinitionOn-Use, DeclarativeOn-UseGraphQL SchemaDeclarativeQueriesCachingDevtools?Polling/IntervalsParallel QueriesDependent QueriesPaginated QueriesInfinite Queries?Bi-directional Infinite Queries???Infinite Query Refetching??Lagged Query Data1??Selectors?Initial DataScroll RecoveryCache ManipulationOutdated Query DismissalRender Optimization2??Auto Garbage Collection??Mutation Hooks?Offline Mutation Support???Prefetching APIs?Query Cancellation???Partial Query Matching3??Stale While Revalidate?Stale Time Configuration???Pre-usage Query/Mutation Configuration4??Window Focus Refetching??Network Status Refetching?General Cache Dehydration/Rehydration?Offline Caching✅ (Experimental)??React Suspense (Experimental)??Abstracted/Agnostic Core?Automatic Refetch after Mutation5??Normalized Caching6???

    更多查看

    总结

    使用 React-Query 可以更加高效的管理来自服务端的请求状态,用更少的代码实现较为复杂的需求,让你的状态管理更优雅。

    参考链接:

    React-Query 官网

    用 react-query 解决你一半的状态管理问题

    react-query


    起源地下载网 » React-Query 让你的状态管理更优雅

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元