缓存react组件在路由器的变化



我有一个计时器组件,即使当react-router路由/settings时,它也应该保持运行,但它会重新渲染,从而导致状态丢失。

Timer.tsx

import React, { useEffect, useRef, useState } from 'react';
import { CircularProgressbarWithChildren } from 'react-circular-progressbar';
import { BsPlayFill, BsPauseFill } from 'react-icons/bs';
import { useSelector } from 'react-redux';
import { convertToMin } from 'renderer/utils/time';
const Timer = () => {
const config = useSelector((state) => state.timer);
const defaultSeconds = config.workTime;
const defaultBreakSeconds = config.breakTime;
const [time, setTime] = useState({});
const timer = useRef(0);
const [paused, setPaused] = useState(true);
const [mode, setMode] = useState('focus');
const seconds = useRef(defaultSeconds);
function countDown() {
seconds.current--;
setTime(convertToMin(seconds.current));
if (seconds.current <= 0) {
clearInterval(timer.current);
restartTimer();
}
}
function restartTimer() {
if (mode === 'focus') {
var sec = defaultBreakSeconds;
setMode('break');
} else {
var sec = defaultSeconds;
setMode('focus');
}
timer.current = 0;
seconds.current = sec;
setTime(convertToMin(sec));
setPaused(true);
}
function startTimer() {
if (seconds.current > 0 && timer.current === 0) {
timer.current = setInterval(() => countDown(), 1000);
setPaused(false);
}
}
function getProgress(sec) {
return Math.floor((seconds.current / sec) * 100);
}
function pauseTimer() {
clearInterval(timer.current);
timer.current = 0;
setPaused(true);
}
useEffect(() => {
let t = convertToMin(defaultSeconds);
setTime(t);
}, []);
return (
<div className="timer-container">
<div className="progressbar">
<CircularProgressbarWithChildren
value={
mode === 'focus'
? getProgress(defaultSeconds)
: getProgress(defaultBreakSeconds)
}
text={`${time.min}:${time.sec}`}
styles={{
trail: { strokeWidth: 1, stroke: '#424656' },
path: {
strokeWidth: 4,
stroke: mode === 'break' ? '#3cc08e' : '#00aefc',
},
text: {
fill: '#00aefc',
},
}}
>
<div className="progress-text">{mode}</div>
</CircularProgressbarWithChildren>
</div>
<div className="action-buttons">
<button type="button">
{paused ? (
<BsPlayFill color="#f0fbff" size={30} onClick={startTimer} />
) : (
<BsPauseFill color="#f0fbff" size={30} onClick={pauseTimer} />
)}
</button>
</div>
</div>
);
};
export default Timer;

App.tsx

export default function App() {
return (
<>
<Provider store={store}>
<Router>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/settings" element={<Menu />} />
</Routes>
</Router>
</Provider>
</>
);
}

是否有可能将组件缓存到后台,以便状态持续并且间隔继续?

既然你在一个单独的组件中有了Timer,那么把它移到路由定义之外呢?这样,当你切换路由时,组件就不会被卸载了。

export default function App() {
return (
<>
<Provider store={store}>
<Timer />
<Router>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/settings" element={<Menu />} />
</Routes>
</Router>
</Provider>
</>
);
}

这里还有一个使用部分代码的沙盒。

如果你不能这样做,因为一个UI约束,使用redux可能解决你的问题,否则,你总是可以利用上下文API来管理状态在一个更高的水平

最新更新