如何使用 setInterval 来触发事件? JavaScript/React-toastify
How to work with setInterval to trigger an event? JavaScript/React-toastify
我有一个 redux 存储,其中包含一个看起来像
的对象
rooms: {
room01 : { timestamp: 10}
room02 : { timestamp: 10}
}
当用户点击按钮时,时间戳设置为 10(通过调度)。如果有时间戳,我倒数到 0,然后在整个应用程序中使用 react-toast
设置通知。
问题是我在 Notification 组件上没有可用的 roomId,因为 Notification 组件必须放在应用程序根目录下,否则它会被卸载并且我的 Notification() 逻辑不起作用。 (我可以访问 Notification 或 App 中的房间,但它出现在一个数组中,例如 ['room01','room02'],它也在 redux 中,但我如何 select 两个房间并访问他们的时间戳以及运行倒计时的功能?)。
基本上我需要检查每个房间的 redux store 中是否有时间戳,如果有,倒数到 0 并显示带有 roomId 的通知。 notification/setinterval 应该在导航到不同页面时起作用。
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}
/>
);
}
除其他方法外,您还可以执行以下操作,但我认为以下方法是最好的,因为它使 Notification 组件更具可重用性,并且更好地利用了职责分离,使您的代码更易于阅读,最重要的是与 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>);
};
我有一个 redux 存储,其中包含一个看起来像
的对象rooms: {
room01 : { timestamp: 10}
room02 : { timestamp: 10}
}
当用户点击按钮时,时间戳设置为 10(通过调度)。如果有时间戳,我倒数到 0,然后在整个应用程序中使用 react-toast
设置通知。
问题是我在 Notification 组件上没有可用的 roomId,因为 Notification 组件必须放在应用程序根目录下,否则它会被卸载并且我的 Notification() 逻辑不起作用。 (我可以访问 Notification 或 App 中的房间,但它出现在一个数组中,例如 ['room01','room02'],它也在 redux 中,但我如何 select 两个房间并访问他们的时间戳以及运行倒计时的功能?)。
基本上我需要检查每个房间的 redux store 中是否有时间戳,如果有,倒数到 0 并显示带有 roomId 的通知。 notification/setinterval 应该在导航到不同页面时起作用。
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}
/>
);
}
除其他方法外,您还可以执行以下操作,但我认为以下方法是最好的,因为它使 Notification 组件更具可重用性,并且更好地利用了职责分离,使您的代码更易于阅读,最重要的是与 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>);
};