简体   繁体   中英

The useReducer is not updating the state value

Hiho!

I thought it would be cool for my page to have a 100% covering black transparent overlay with text when its waiting for data from the server. So it its waiting for data a 30% black overlay with the text "Loading...". I wrote the context and provider and while it works it is a bit too fast:-). I want it to hide the overlay with a delay for 1500s (or less), so I tried changing the useState to a useReducer and implement the logic in setDisplayStateFunc:

import { createContext, useReducer, useState } from "react";

function useOverlay(display) {

    async function setDisplayStateFunc(state, action) {

        await new Promise(resolve => setTimeout(resolve, 1500));
        console.log(`returning: ${action}`);
        return action;
    }

    const [displayState, setDisplayState] 
        //= useState(display);
        = useReducer(setDisplayStateFunc, display);

    return { displayState, setDisplayState }
}

const OverlayContext = createContext();

function LoaderOverlay({ children, display = 'block' }) {

    const { displayState, setDisplayState } = useOverlay(display);

    return (
        <OverlayContext.Provider value={{ displayState, setDisplayState }}>
            <div className="loader" style={{ "display": displayState }}>
                <span>Loading ...</span>
            </div>

            {children}
        </OverlayContext.Provider>
    )
}

export { LoaderOverlay, OverlayContext };

The console.log I have there is outputting the right values, and out and about in my componets i use it by setting up useContext and then setDisplayState('none') after I'm done loading.

It works with useState, but I want a small delay. Where did I go wrong?

I don't think useReducer support async function. The notion of side effect should generally not be inside the reducer.

I would suggest using a useEffect to handle this inside of LoaderOverlay

import { createContext, useReducer, useState } from "react";

function useOverlay(display) {

    async function setDisplayStateFunc(state, action) {
        return action;
    }

    const [displayState, setDisplayState]
        = useReducer(setDisplayStateFunc, display);

    return { displayState, setDisplayState }
}

const OverlayContext = createContext();

function LoaderOverlay({ children, display = 'block' }) {

    const { displayState, setDisplayState } = useOverlay();

    useEffect(() => {
    async function waitSomeTime() {
      await new Promise(resolve => setTimeout(resolve, 1500));
      setDisplayState()
    }
    waitSomeTime()
    }, [setDisplayState])

    return (
        <OverlayContext.Provider value={{ displayState, setDisplayState }}>
            <div className="loader" style={{ "display": displayState }}>
                <span>Loading ...</span>
            </div>

            {children}
        </OverlayContext.Provider>
    )
}

export { LoaderOverlay, OverlayContext };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM