Используйте пользовательский интерфейс с Таймером Реакции - PullRequest
0 голосов
/ 23 марта 2020

В моем проекте я использую 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?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...