В моем проекте я использую response-countdown-circle-timer ссылка - в основном это таймер. Чтобы получить хорошую анимацию прошедшего времени, вам нужно использовать css, и я хотел бы интегрировать их в пользовательский интерфейс материала. Первоначально у меня был такой метод и стиль css:
const renderTime = time => {
const currentTime = useRef(time);
const prevTime = useRef(null);
const isNewTimeFirstTick = useRef(false);
const [_, setOneLastRerender] = useState(0);
if (currentTime.current !== time) {
isNewTimeFirstTick.current = true;
prevTime.current = currentTime.current;
currentTime.current = time
} else {
isNewTimeFirstTick.current = false;
}
// force one last re-render when the time is over to tirgger the last animation
if (time === 0) {
setTimeout(() => {
setOneLastRerender(val => val + 1);
}, 20);
}
const isTimeUp = isNewTimeFirstTick.current;
return (
<div className="time-wrapper">
<div
key={time}
className={`time ${isTimeUp ? 'up' : ''}`}
>
{time}
</div>
{prevTime.current !== null && (
<div
key={prevTime.current}
className={`time ${!isTimeUp ? 'down' : ''}`}
>
{prevTime.current}
</div>
)}
</div>
);
};
стиль:
.time-wrapper {
position: relative;
// change width and height if needed
width: 80px;
height: 60px;
}
.time-wrapper .time {
position: absolute;
left:0;
top: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
transform: translateY(0);
opacity: 1;
transition: all .2s;
}
.time-wrapper .time.up {
opacity: 0;
transform: translateY(-100%)
}
.time-wrapper .time.down {
opacity: 0;
transform: translateY(100%)
}
Чтобы иметь возможность использовать MUI, я изменил их на:
const styles = theme => ({
wrapper: {
position: "relative",
width: "80px",
height: "60px",
time: {
position: "absolute",
left:0,
top: 0,
width: "100%",
height: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center",
transform: "translateY(0)",
opacity: 1,
transition: "all .2s",
up: {
opacity: 0,
transform: "translateY(-100%)"
},
down: {
opacity: 0,
transform: "translateY(100%)"
}
}
}
});
const renderTime = (classes, time) => {
const currentTime = React.useRef(time);
const prevTime = React.useRef(null);
const isNewTimeFirstTick = React.useRef(false);
const [_, setOneLastRerender] = React.useState(0);
if (currentTime.current !== time) {
isNewTimeFirstTick.current = true;
prevTime.current = currentTime.current;
currentTime.current = time;
} else {
isNewTimeFirstTick.current = false;
}
if (time === 0) {
setTimeout(
() => {
setOneLastRerender(val => val + 1);
},
20
);
}
const isTimeUp = isNewTimeFirstTick.current;
return (
<div className={classes.wrapper}>
<div
key={time}
className={isTimeUp ? classes.wrapper.time.up : classes.wrapper.time}
>
{time}
</div>
{prevTime.current !== null && (
<div
key={prevTime.current}
className={!isTimeUp ? classes.wrapper.time.down : classes.wrapper.time}
>
{prevTime.current}
</div>
)}
</div>
);
};
Я создал свой компонент:
const ResponseTimer = (props) => {
const {classes} = props;
return (
<CountdownCircleTimer
isPlaying={true}
durationSeconds={30}
renderTime={time => renderTime(classes, time)}
initialRemainingTime={10}
colors={[
[green[500], .33],
[yellow[500], .33],
[red[500]]
]}
/>
);
};
ResponseTimer.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(ResponseTimer);
И вот моя проблема, потому что он работает только в течение нескольких секунд, после чего выдает исключение:
TypeError: Cannot read property 'up' of undefined
renderTime
src/routes/Threads/View/Sidebar/ResponseTimer.js:72
69 | <div className={classes.wrapper}>
70 | <div
71 | key={time}
> 72 | className={isTimeUp ? classes.wrapper.time.up : classes.wrapper.time}
| ^ 73 | >
74 | {time}
75 | </div>
View compiled
renderTime
src/routes/Threads/View/Sidebar/ResponseTimer.js:94
91 | <CountdownCircleTimer
92 | isPlaying={true}
93 | durationSeconds={30}
> 94 | renderTime={time => renderTime(classes, time)}
| ^ 95 | initialRemainingTime={10}
96 | colors={[
97 | [green[500], .33],
View compiled
Знаете ли вы, как интегрировать пользовательский css с MUI?