react: сохранение состояний при функциональном программировании

Рейтинг: 1Ответов: 0Опубликовано: 23.03.2023

ситуация следующая (как я ее понимаю):

при определении функционального компонента (чтоб не захламлять специально его максимально вычистил)

export interface IProps {
    title       : string,
    timer       : number
}

const Component = (props: IProps ) => {
  // контроль состояний
  const [states, setCountdownParams] = useState<IStates>({
    a: props.timer,
    b: true
  });

  return <></>
}

при передаче новых параметров компоненту

<Component title="t1" timer=10 /> => <Component title="t2" timer=10 />

происходит установка заново состояний, т.е.

  const [states, setCountdownParams] = useState<IStates>({
    a: props.timer,
    b: true
  });

как этого избежать?

мне хотелось бы, чтоб компонент использовал старые значения, т.е. состояния не обновлялись бы.

Вариант, который приходит в голову - добавить колбэк в класс, который будет возвращать актуальное состояние, таким образом всегда можно при новом вызове компонента использовать старое состояние - но как по мне - это жуткий костыль

А как это сделать правильно?

Объясню ситуацию на прикладной задаче - у меня есть компонент с обратным отсчётом, когда обратный отсчёт заканчивается, то он должен продолжать отобраться корректно. Остановка обратного отсчёта сделана через props, в результате начинает отобраться начальное время (из-за причин описанных выше):

interfaces:

import {CSSProperties} from 'react';

// интерфейс для пропсов
export interface IPropsTaskHeader {
    title       : string,               // название задачи
    deadline    : number,               // время выполнения задачи (в секундах)
    active?     : boolean,              // активна ли задача
    onStop?     : any                   // колбэк на завершение задачи
}

// интерфейс для состояний
export interface IStatesTaskHeader {    
    timer_state     : number,           // идентификатор состояния таймера времени выполнения задачи
    timer_global    : number,           // текущее глобальное значение таймера время выполнения задачи (в миллисекундах)
    timer_local     : number            // текущее локальное значение таймера время выполнения задачи (в миллисекундах)
}

// интерфейс для стилей
export interface IDataCountdown {
    [key: number]: {
        deadline    : number,           // время срабатывания следующего таймера
        style       : CSSProperties     // стили для счётчика обратного отсчёта
    };
}

component:

// компонент заголовка задачи (с элементами управления)
const TaskHeader = (props: IPropsTaskHeader) => {
  // контроль состояний
  const [states, setCountdownParams] = useState<IStatesTaskHeader>({
    timer_state   : 0,
    timer_global  : Date.now() + 1000 * props.deadline,
    timer_local   : 1000 * props.deadline
  });

  // стили для разных состояний
  const styles: IDataCountdown = {
    0: {deadline: 60, style: {color: "#000000", textAlign: "center"}},
    1: {deadline: 10, style: {color: "#bb0000", textAlign: "center"}},
    2: {deadline: 0, style: {color: "#bb0000", textAlign: "center", animation: "neon 1s infinite"}}
  }

  // колбэк: изменение времени таймера
  const handleChangeTimer = (timer: any) => {
    const t: number = 1000 * styles[states.timer_state]?.deadline;
    if (timer <= t) {
      setCountdownParams({
        timer_state   : states.timer_state + 1,
        timer_global  : Date.now() + t,
        timer_local   : t
      });
    }
  }

  // колбэк: завершение работы таймера
  const handleFinishTimer = () => {
    setCountdownParams({
      timer_state   : states.timer_state,
      timer_global  : Date.now(),
      timer_local   : 0
    });      

    props.onStop?.();
  }

  // отрисовать компонент
  return (
    <div className="task-header">
      <div className="task-header-title">{props.title}</div>
      {
        props.active ? 
          <Statistic.Countdown title="Время выполнения" value={states.timer_global} format="mm:ss" valueStyle={styles[states.timer_state].style} onChange={handleChangeTimer} onFinish={handleFinishTimer} className="task-header-statistics" /> : 
          <Statistic title="Время выполнения" value={new Date(states.timer_local).toISOString().slice(-10, -5)} valueStyle={styles[states.timer_state].style} className="task-header-statistics" />
      }
    </div>
  );
}

Ответы

Ответов пока нет.