两个列表展现的内容会串?尝试写个hook来处理!

131 阅读2分钟

前言:这里是一个菜鸡前端,一直都有想法写写文章,想要一点一点进步,但是不知道要写点什么。想来想去还是记录一下遇到的问题,还有解决的思路。有更好的思路或者不同的方法,欢迎大家交流。

背景:之前在做小程序开发时,在预约管理中有多个tab,在不同tab切换时,列表的内容也会根据tab变化。测试当时提了一个bug,表示在来回切换tab时,不同的tab中的数据会互相串。当时大致的逻辑如下:

    const [dataSource, setDataSource] = useState([]);
    const fetch = async (type) => {
        const res = await getData(type);
        setDataSource(res?.data || []);
    }
    
    useEffect(()=>{
        fetch(type);
    }, [type])
    
    return (
        <View>
            <Tabs {...tabProps} />
            <View>
                {dataSource.map((item) => (<Item {...item}/>))}
            </View>
        </View>
    )

然后查了一下,看到了network中先发送的请求后到达,这就会导致dataSource会被覆盖掉,所以数据就串了。

解决思路:询问了一下公司的前辈,他说这类问题的话,可以在请求发出去的时候记录一个id,如果请求时的id和记录的id不一致的话,就不做处理,改动后如下:

    const [dataSource, setDataSource] = useState([]);
    const requestIdRef = useRef(null);
    const fetch = async (type) => {
        const id = generateId();
        requestIdRef.current = id
        const res = await getData(type);
        if(requestIdRef.current !== id) {
            return;
        }
        setDataSource(res?.data || []);
    }
    
    useEffect(()=>{
        fetch(type);
    }, [type])
    
    return (
        <View>
            <Tabs {...tabProps} />
            <View>
                {dataSource.map((item) => (<Item {...item}/>))}
            </View>
        </View>
    )

这么一来确实处理了这个问题。但是还有许多场景也是类似的,如果后续还有类似的场景,这种代码不得每次都写一遍?于是冒出来一个想法,写一个hook来处理,就叫它useNewestRequest好了(随便取

实现:实现的思路倒是没有什么变化,依旧是通过记录id来进行区分,最后通过返回一个方法来进行调用。以下是实现:

    const useNewestRequest = ({ request, onSuccess, onError }) => {
    const requestId = useRef(null);

      /**
       * 接口调用方法
       * @param {接口传参} params
       * @param  {额外的传参,会原封不动地回调返回回去} args
       * @returns
       */
    const run = async (params, ...args) => {
        const newId = generateId();
        requestId.current = newId;
        const res = await request(params).catch((err) => {
          onError?.(err);
        });
        if (!res) {
          return;
        }
        if (requestId.current !== newId) {
          return;
        }
        onSuccess?.(res, ...args);
    };

      return { run };
};

至于使用嘛,针对上面的例子就可以这样改造:

    const [dataSource, setDataSource] = useState([]);
    
    const { run } = useNewestRequest({
        request: getData,
        onSuccess: (res) => {
            setDataSource(res?.data || []);
        },
        onError: () => {
            setDataSource([]);
        }
    })
    
    useEffect(()=>{
        run(type);
    }, [type])
    
    return (
        <View>
            <Tabs {...tabProps} />
            <View>
                {dataSource.map((item) => (<Item {...item}/>))}
            </View>
        </View>
    )

这样一来就搞定了!

后记:希望以此为契机,能够再多记录一些问题,多写一些文章,记录自己的成长过程。