React-Hook实现数据获取

前言

为了实现一个获取数据并进行管理。

为了实现在函数式组件里下拉获取数据想尽方法。最后使用

react-infinite-scroller.还是在类里面写好了。

自定义异步Hook

封装一个自定义Hook

import {useEffect,useState,useReducer} from 'react';

import {Axios_get} from '../api/server';
import { listReducer } from './reducers/listReducer';

import { requestList, receiveList, receiveError,noMore } from './actions/listActions';


function useListHook(initialUrl) {

    const [url,setUrl] = useState(initialUrl);

    const [listState,listDispatch] = useReducer(listReducer,{
        isLoading:false,
        isError:false,
        hasMore:true,
        message:'',
        dataSource:[],
    });

    useEffect(() => {
        let didCancel = false;
        Axios_get(url,(rs)=>{
            listDispatch(requestList());
            console.log(rs)
            if(!rs.data){
                if(!didCancel){
                    listDispatch(receiveError(rs));
                }
            }
            if(rs.data.list.length===0){
                listDispatch(noMore(rs));
            }
            if(rs.status!==0){
                if(!didCancel){
                    listDispatch(receiveList(rs.data))
                }
            }else{
                if(!didCancel){
                    listDispatch(receiveError(rs));
                }
            }
        });
        return () => {
            didCancel = true;
        };
    },[url])

    const handlerSetUrl = (url)=>setUrl(url);

    return [listState,handlerSetUrl]
}
export {useListHook}

本来是想要暴露出的handlerSetUrl 通过改变url进行下一页的获取,但是老是出现错误。

唉,还有待理解react。

上面这个把 reducer 和action 写在另外的地方

IntersectionObserver

看了一些方案:

本来的希望是在需要list数据的组件底部,放入一个div 以指示已经到达底部,需要改变url获取新数据了,但是出现了错误。

说说这个IntersectionObserver 吧。

这个是一个新的web api 。我们可以去查看文档。Observert

做要用于监听一个元素是否在可视范围。以及出现在可视范围的回调函数,和离开可视范围的回调。

阮一峰老师也有介绍

可以利用这个来实现一个虚拟无限列表吧。

import React,{useState,useEffect,useRef} from 'react'

export default function Observe({callback}) {

    const obRef = useRef();
    const [observer, setObserver] = useState(null);

    useEffect(() => {
        const initiateScrollObserver = (_dom) => {
            const io = new IntersectionObserver(callback);
            if (_dom) {
                io.observe(_dom);
            }
            setObserver(io);
        }

        initiateScrollObserver(obRef.current);

        const resetObservation = () => {
            observer && observer.disconnect();
        }
        return () => {
            resetObservation();
        };
    }, [observer,callback])

    return (
        <div ref={obRef} hidden></div>
    )
}

企图通过当这个div出现在视口的时候调用更改组件的url来获取新的数据,但是出现了更改setate过深?的错误。

。。。。

最后使用插件。

import React, { Component } from 'react';

import InfiniteScroll from 'react-infinite-scroller';

import ListItem from './ListItem';
import Spin from './Spin';
import Error from './Error';
import { Axios_get } from '../api/server';


export default class List extends Component {

    constructor(props){
        super(props);
        this.state = {
            isLoading:false,
            isError:false,
            hasMore:true,
            message:'',
            dataSource:[],
            page:1,
            pageSize:5,
        }
    }
    componentDidMount() {
        this.handleLoad();
    }

    handleLoad = ()=>{
        let {page,pageSize,dataSource} = this.state;
        this.setState({
            isLoading:true,
        })
        let url = `/movies/${page}/${pageSize}`;
        Axios_get(url,(rs)=>{
            console.log(rs)
            if(!rs.data){
                this.setState({
                    isLoading:false,
                    isError:true,
                    message:rs.toString()
                })
            }else{
                const {list,has_next} = rs.data;
                if(!has_next){
                    this.setState({
                        isLoading:false,
                        hasMore:false,
                        message:'No More',
                    })
                }
                if(rs.status===200 && has_next){
                    dataSource = dataSource.concat(list);
                    page = ++page;
                    this.setState({
                        isLoading:false,
                        hasMore:true,
                        dataSource,
                        page,
                    })
                }
            }
        })
    }


    render() {
        const {dataSource,isError,isLoading,hasMore,message} = this.state;
        const items = dataSource.map(item=>
            <ListItem key={item.id} item={item}/>
        )
        return (
        !isError?<InfiniteScroll
        threshold={0}
        className="rush-list"
        initialLoad={false} 
        pageStart={0}
        loadMore={this.handleLoad}
        hasMore={!isLoading && hasMore}>
        {items}
        {isLoading && hasMore&&(
            <div className="loading-container">
                <Spin />
            </div>
        )}
    </InfiniteScroll>:<Error message={message}/>
    )}
}


奖励一下