Home > other >  React - update state with timeout in reducer
React - update state with timeout in reducer

Time:07-18

Can anyone help me to update state with timeout in react reducer.

I don't have much experience even with pure javascript, so I can hardly find an answer myself at this moment.

In my first ever react app (with useContex and useReducer) i have simple BUTTON checkbox with onClick function to dispatch type in reducer:

     <ToggleButton
                                        className="mb-2"
                                        id="Getdocs"
                                        type="checkbox"
                                        variant="outline-secondary"
                                        size="sm"
                                        checked={Getdocs}
                                        onChange={(e) => Getdocsaction()}
                                    >
                                        Render documents
                                    </ToggleButton>

In my context.js i have:

import React, { useContext, useReducer} from 'react'
import reducer from './reducer'

const AppContext = React.createContext()

const initialState = {

    .
    .
    .
    Showdocs: false,
    .
    .
    .

}


const AppProvider = ({ children }) => {

    const [state, dispatch] = useReducer(reducer, initialState)
...
    const Getdocsaction = () => {
        dispatch({ type: 'GET_DOCS' })
    }
...
 

    return (
        <AppContext.Provider
            value={{
                ...state,
                Getdocsaction
            }}
        >
            {children}
        </AppContext.Provider>
    )
}

export const useGlobalContext = () => {
    return useContext(AppContext)
}

export { AppContext, AppProvider }

In reducer.js i have:

const reducer = (state, action) => {

  
    if (action.type === 'GET_DOCS') {
        let newPassports = state.oldDocs.filter((doc) => doc.passport === true);
  
        if (newPassports.length === 0) {
            state.Passports = []
            state.Showdocs = true
            state.Getdocs = false /uncheck checkbox button


            setTimeout(() => {
                state.Showdocs = false //wont update this
                console.log("setTimeout fired")  //logs in console after 5 secs
            }, 5000)

            return { ...state }
        }

        if (newPassports.length !== 0) {

            return { ...state, Passports: newPassports, Showdocs: true, Getdocs: !state.Getdocs }
        }

        return { ...state }
    }


  

    throw new Error('no matching action type')
}

export default reducer

Finally, in my App.js i check if Showdocs is true or false and return the rest (return the passports from updated array or bootstrap alert if there is no values in array (Passport.length === 0) )

What i am trying to achieve is that when i have empty Passports array i want set Showdocs: true (in order to show alert msg) and set it back to false after 5 secs (in order to remove msg ...)

Any help is welcome and even keywords by which i could research this issue. Thank you.

CodePudding user response:

I think you should implement an action that basically updates the state with this state.Showdocs = false and then dispatch this action inside a setTimeout.

So basically change Getdocsaction to this:

const Getdocsaction = () => {
    dispatch({ type: 'GET_DOCS' })
    setTimeout(() => {dispatch({type: 'The action that sets Showdocs to false'})}, 5000);
}

CodePudding user response:

Reducers are intended to be “pure” and synchronous, and they shouldn't mutate input arguments. Since mutating state after a delay is a side-effect, you should consider instead handling this in a useEffect hook separately.

E.g.:

const SomeComponent = () => {
  const [state, dispatch] = useReducer(reducer)
  const { hideDocsAfterDelay } = state

  useEffect(() => {
    if (!hideDocsAfterDelay) return

    const timer = setTimeout(() => {
      dispatch({ TYPE: "HIDE_DOCS" })
    }, 5000)

    return () => { clearTimeout(timer) }
  }, [hideDocsAfterDelay])

  // …
}

In this scenario, you would set a hideDocsAfterDelay property in your state to trigger the timer and another action handler that would set showDocs and hideDocsAfterDelay to false.

  • Related