React. Обновить значение внутри setInterval по внешней переменной

Задачка поначалу показалась весьма простой, но когда начал работать с таймером - что-то пошло не так. К примеру:

const [number, setNumber] = useState(4);

useEffect(() => {
    setInterval(out, 1500);
}, []);

const out = () => {
    console.log(number);
};

В общем нужно, чтобы при смене number в консоль выводилось новое значение, а то у меня постоянно выводится 4. Пробовал делать clearInterval и создавать новый таймер при изменении того же number, но, в итоге, у меня существовало 2 таймера. Подскажите как оптимально решить задачку.


Ответы (1 шт):

Автор решения: Konstantin Modin

Можно например так:

import React from "react";

const Timer = () => {
  const [number, setNumber] = React.useState(1);

  React.useEffect(() => {
    // таймер пересоздаётся каждый раз когда обновляется number
    const id = setInterval(() => setNumber(number + 1), 1000);
    return () => {
      clearInterval(id);
    };
  }, [number]);

  return <div>Number is {number}</div>;
};

export default Timer;

Но даже проще можно написать так:

import React from "react";

const Timer = () => {
  const [number, setNumber] = React.useState(1);

  React.useEffect(() => {
    setTimeout(() => setNumber(number + 1), 1000);
  }, [number]);

  return <div>Number is {number}</div>;
};

export default Timer;

Потому что в первом варианте из-за особенностей реакта каждый раз пересоздаётся таймер. С одним таймером не будет ре-рендерится обновлённое значение (если оно должно быть не только в консоли):

import React from "react";

const Timer = () => {
  const [number, setNumber] = React.useState(1);

  let n = 0;
  React.useEffect(() => {
    // таймер создаётся 1 раз
    const id = setInterval(() => {
      console.log(n++);
    }, 1000);

    return () => {
      clearInterval(id);
    };
  }, []);

  return (
    <>
      <div>Number is {number}</div>
      <div>n is {n}</div>
    </>
  );
};

export default Timer;

Последний вариант - это не Реакт стиль -> bad practice

→ Ссылка