How to work with setInterval to trigger an event? JavaScript/React-toastify Code Answer

Hello Developer, Hope you guys are doing great. Today at Tutorial Guruji Official website, we are sharing the answer of How to work with setInterval to trigger an event? JavaScript/React-toastify without wasting too much if your time.

The question is published on by Tutorial Guruji team.

I have a redux store that contains an object that looks like

rooms: {
    room01 : { timestamp: 10}
    room02 : { timestamp: 10}
}

When a user clicks on a button the timestamp is set to 10 (via dispatch). If there is a timestamp I count down to 0 and then set a Notification using react-toast across the app. The problem is I don’t have roomId available on Notification component because Notification component has to be placed at app root otherwise it’s get unmounted and my Notification() logic doesn’t work. (I could access the rooms in Notification or App but it comes in an array for eg [‘room01’, ‘room02’] which is also in redux but how do I select both rooms and access their timestamp as well as run the function to count down?).

Basically I need to check if there is timestamp in redux store for each room and if there is, count down to 0 and display notification with the roomId. The notification/setinterval should work while navigating to different pages.

My app component 

import React from 'react';
import { Route, Switch, BrowserRouter } from 'react-router-dom';

import Home from './Home';
import 'react-toastify/dist/ReactToastify.css';
import Notification from '../features/seclusion/Notification';

const App = () => {
    return (
        <div>
            <Notification /> // if I pass in room id like so roomId={'room02'} I cant get it to work for one room
            <BrowserRouter>
                <Switch>
                    <Route exact path="/room/:id" component={Room} />
                    <Route exact path="/" component={Home} />
                </Switch>
            </BrowserRouter>
        </div>);
};

export default App;
import React, { useState, useEffect } from 'react';
import { useSelector } from 'react-redux';
import 'react-toastify/dist/ReactToastify.css';
import { ToastContainer, toast, Slide } from 'react-toastify';
import moment from 'moment';

export default function Notification() {
    
    const timestamp =  useSelector(state =>  state.rooms); // need to get timestamp  for room01 and room02 
    
    const [timestamp, setTimestamp] = useState(null);
    const [timerId, setTimerId] = useState(null);

    const notify = () => {
        toast(<div>alert</div>,
            {
                position: "top-center",
            });
    }; 

    useEffect(() => {
        if (timestamp) {
            const id = setInterval(() => {
               setTimestamp((timestamp) =>  timestamp - 1)
            }, 1000)

            setTimerId(id);

        }
        return () => {
            clearInterval(timerId);
        };
    }, [timestamp]);

    useEffect(() => {
        if(timestamp === 0){
            notify();
            clearInterval(timerId); 
        }
    }, [timestamp])

    return (
        <ToastContainer
            newestOnTop={true}
            transition={Slide}
            autoClose={false}
        />
    );

}

Answer

You could do the following among other approaches, but i think the following is the best because it makes the Notification component more reusable, and also it makes better use of the separation of responsibilities, makes your code easier to read, and most importantly is aligned with the declarative mindset of React.

const App = () => {
    const rooms = state.rooms // this is not redux syntax but i will leave that to you
    return (
        <div>
            {Object.entries(rooms).map(([roomId, roomDetails]) => {
              const {timestamp} =  roomDetails;
              // Obviously you now need to modify your Notification component to handle these props
              return <Notification 
                      timestamp={timestamp} 
                      roomId={roomId} // actually its better to create the Notification component without the roomId prop and use the roomId to induce the message prop, this makes Notification component more reusable across other components 
                      key={`${roomId}-${timestamp}`} 
                      message="You might send message here instead of doing that inside the Notification component" 
                    />
                    // You might be interested to rename Notification to DelayedNotification or something else 
            }}
            <BrowserRouter>
                <Switch>
                    <Route exact path="/room/:id" component={Room} />
                    <Route exact path="/" component={Home} />
                </Switch>
            </BrowserRouter>
        </div>);
};
We are here to answer your question about How to work with setInterval to trigger an event? JavaScript/React-toastify - If you find the proper solution, please don't forgot to share this with your team members.

Related Posts

Tutorial Guruji