skip to Main Content

I am working on adding some progress indicators to my React web application.

So far I have been using the following as a basis.
react-suspense-data-fetching.

export interface ISuspender<T> {
    read(): T;
}

const createSuspender = <T,>(promise: Promise<T>): ISuspender<T> => {
    let status: string = 'pending';
    let response: T;

    const suspender: Promise<void> = promise.then(
        (result) => {
            status = "susccess";
            response = result;
        },
        (error) => {
            status = "error";
            response = error;
        }
    );
    const read = (): T => {
        switch (status) {
            case 'pending':
                throw suspender;
            case 'error':
                throw response;
            default:
                return response;
        }
    }
    return { read }
}

const getSetsSuspender: ISuspender<Scry.Set[]> = createSuspender(Scry.Sets.all());

export const MtgSetList: React.FunctionComponent = () => {
    const sets: Scry.Set[] = getSetsSuspender.read();

    return (
        <SetList sets={sets} />
    )
}

It works but not as well as I would like it to. For starters the data returned is not stored in state so I am unable to interact with it and add filtering capabilities.

I am also not a huge fan of how the suspender needs to be declared outside of the component.

Ideally I would like to write the MtgSetList like this

export const MtgSetList: React.FunctionComponent = () => {
    const getSetsSuspender: ISuspender<Scry.Set[]> = createSuspender(Scry.Sets.all());
    const [sets, setSets] = React.useState<Scry.Set[]>();

    useEffect(() => {        
        setSets(getSetsSuspender.read());
    }, [getSetsSuspender]);
   
    return (
        <SetList sets={sets} />
    )
}

Any and all advice would be greatly appreciated.

2

Answers


  1. Chosen as BEST ANSWER

    While still not perfect I have gotten it somewhat working by creating the suspender instance outside of the component. That was causing some weird refreshing behavior. So I added a check to see if I needed to retrieve the data or not.

    const suspender = createSuspender(Scry.Sets.all());
    
    export const MtgSetList: React.FunctionComponent = () => {
        const [sets, setSets] = React.useState<Scry.Set[]>();
    
        if(!sets){       
            const fetchedSets = suspender.read();
            setSets(fetchedSets);
        }   
        return (
            <SetList sets={sets} />
        )
    }
    

  2. Move getSetsSuspender inside a useEffect hook. Then, use getSetsSuspender.read() to retrieve the data and set the state using setSets.

    export const MtgSetList: React.FunctionComponent = () => {
        const [sets, setSets] = React.useState<Scry.Set[]>([]);
    
        useEffect(() => {
            const getSetsSuspender: ISuspender<Scry.Set[]> = createSuspender(Scry.Sets.all());
    
            try {
                const fetchedSets = getSetsSuspender.read();
                setSets(fetchedSets);
            } catch (error) {
            }
        }, []);
    
        return (
            <SetList sets={sets} />
        );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search