React-Query源码探秘 4-Query(核心类)

553 阅读2分钟

专栏目录: 全网最细 React-Query源码探秘 - 不月阳九的专栏 - 掘金 (juejin.cn)

Query —— React-Query的底层核心类

主要功能 :网络数据请求、状态变化的处理、内存回收。

Query的工作机制

  1. 每个Query通过queryKey进行区别, Query上保存了请求回来的后端数据,一个请求方法API对应一个Query。
  2. 同一个数据(Query)可能会被多个react组件订阅, 每个react组件作为一个Observer,存放在Query的 observers属性中.
  3. 当Query中的数据发生更新 会遍历observers,通知所有订阅的React组件,更新页面.
  4. Observer挂载时会传入组件的setState函数作为updater,以此执行更新.

image.png

网络数据请求

Query发起请求时,会创建一个retryer,用来真正发起请求,详见第五篇Retryer

状态变化处理

这里使用的是Redux的 dispatch action reducer一套, 当请求结束(比如成功) 会创建一个success的action, dispatch分发到Query上, reducer执行对应的action,改变Query的状态

内存回收

query作为缓存,当然有有效时间,当我们配置的cacheTime后,在Query初始化时会创建一个setTimeout,定时后从缓存中清除Query,并且通知所有的observer,同时通知QueryCache,删除这个Query。

Query的状态

分为请求状态和查询状态,请求结束后会针对不同的情况更改状态 ,并return为结果,我们可以在外层查询到状态

export type QueryStatus = 'loading' | 'error' | 'success' // 当前单次请求状态
export type FetchStatus = 'fetching' | 'paused' | 'idle'// 查询状态 表示是否在持续查询

源码解析(仅取重要部分)

(以下非源码 而是自己手写的迷你版React-Query 方便大家理解)

export class Query {
        ...
    this.cache = config.cache
    queryKey: QueryKey // 唯一key
    options: QueryOptions // 配置项
    state: QueryState // query的状态
    observers: QueryObserver[] // 订阅者
    private retryer?: Retryer // 请求器
    private GCtimer?: ReturnType<typeof setTimeout>// 垃圾回收timer
    
    
    constructor(config: QueryConfig) {
         ...
        this.state = config.state || getDefaultQueryState()
        console.log('创建Query', config.options.queryKey);
        this.updateGCTimer() // 垃圾回收定时器
    }
    
    addObserver(){...} // 添加一个ob
    
    removeObserver(){...} // 移除一个ob
    
    destory(){...} // query自我销毁
    
    updateGCTimer() { // 垃圾回收定时器
        const cacheTime = this.options.cacheTime
        if (!cacheTime) return
        this.GCtimer = setTimeout(() => {
            this.destory()
            clearTimeout(this.GCtimer)
        }, cacheTime)
    }
    
    fetch(){// 请求数据
    ...

        this.retryer = createRetryer({// 通过创建retryer进行请求
            fn: fetchFn,
            // abort: false, // 终止指针
            onSuccess,
            onError,
            onFail,
            onPause,
            onContinue,
            retry: options.retry, // 重复次数
            retryDelay: options.retryDelay,// 延迟时间
        })

        // 将retryer返回的结果保存 并返回
        this.promise = this.retryer.promise

        return this.promise
    
    
    } 
    
        // 根据action创建创建不同的reducer 来修改当前query的状态
    private dispatch(action: Action): void {
        const reducer = (state: QueryState): QueryState => {
            switch (action.type) {
                case 'fetch':
                    console.log('发起请求事件');
                    return {
                        ...state,
                        fetchFailureCount: 0,
                        fetchStatus: 'fetching',
                        status: 'loading'
                    }
                case 'success':
                    console.log('请求成功事件');
                    return {
                        ...state,
                        data: action.data,
                        dataUpdateCount: state.dataUpdateCount + 1,
                        dataUpdatedAt: action.dataUpdatedAt ?? Date.now(),
                        error: null,
                        status: 'success',
                        fetchStatus: 'idle'
                    }
                case 'failed':
                    console.log('请求失败事件');
                    return {
                        ...state,
                        fetchFailureCount: state.fetchFailureCount + 1,
                    }
                case 'error':
                    const error = action.error
                    console.log('请求错误事件');
                    return {
                        ...state,
                        error: error,
                        errorUpdateCount: state.errorUpdateCount + 1,
                        fetchFailureCount: state.fetchFailureCount + 1,
                        status: 'error',
                        fetchStatus: 'idle'
                    }
                case 'pause':
                    console.log('请求暂停事件');
                    return {
                        ...state,
                        fetchStatus: 'paused',
                    }
                case 'continue':
                    console.log('请求继续事件');
                    return {
                        ...state,
                        fetchStatus: 'fetching',
                    }
            }
        }

        this.state = reducer(this.state) //修改query的state

        // 通知所有的observer  state更新了  observer重新渲染组件
        this.observers.forEach((observer) => {
            observer.onQueryUpdate(action)
        })

    }
}