В rxjs не получается отменить действие interval() ни с помощью takeWhile, ни с помощью unsubscribe()
Проблема в этом куске кода:
useEffect(() => {
console.log(status);
let sub = interv.pipe(
takeWhile(() => status === "run")
).subscribe((v) => {
setS((actual) => actual + 1)
});
if (status !== "run") {
sub.unsubscribe();
}
console.log(status);
}, [status]);
Полный код:
import "./App.css";
import React, { useEffect, useState } from "react";
import { HashRouter } from "react-router-dom";
import { interval } from "rxjs";
import { take, takeUntil, takeWhile } from 'rxjs/operators';
const App = React.memo((props) => {
console.log('rerendered');
// const [time, setTime] = useState({ h: 0, m: 0, s: 0 });
const [s, setS] = useState(0);
const [m, setM] = useState(0);
const [h, setH] = useState(0);
const [interv, setInterv] = useState(interval(1000));
const [status, setStatus] = useState("stop");
const [touchTime, setTouchTime] = useState(0);
useEffect(() => {
console.log(status);
let sub = interv.pipe(
takeWhile(() => status === "run")
).subscribe((v) => {
setS((actual) => actual + 1)
});
if (status !== "run") {
sub.unsubscribe();
}
console.log(status);
}, [status]);
// functin start starts the stopwatch
const start = () => {
setStatus("run");
};
// function stop stops the stopwatch
const stop = () => {
setStatus("stop");
};
return (
<div className="App">
<div>
<h1>Stopwatch</h1>
<Display s={s} m={m} h={h} />
<Buttons
start={start}
status={status}
s={s}
stop={stop}
/>
</div>
</div>
);
});
const Display = ({s, m, h}) => {
return (
<div className="watch">
<span>{h >= 10 ? h : "0" + h}</span>
:
<span>{m >= 10 ? m : "0" + m}</span>
:
<span>{s >= 10 ? s : "0" + s}</span>
</div>
);
};
const Buttons = (props) => {
return (
<div className="stopWatchButtons">
{props.status === "stop" && <button onClick={props.start}>Start</button>}
{(props.status === "run" || props.status === "reset") && (
<button onClick={props.stop} className="stopButton">
Stop
</button>
)}
<button onClick={props.wait}>Wait</button>
<button onClick={props.reset}>Reset</button>
</div>
);
};
const AppWrapper = () => {
return (
<HashRouter>
<App />
</HashRouter>
);
};
export default AppWrapper;
Заранее спасибо!
Ответы (1 шт):
Автор решения: classmate
→ Ссылка
useEffect(() => {
let sub = interv.pipe(
takeWhile(() => status === "run")
).subscribe((v) => {
setS((actual) => actual + 1)
});
return () => {
sub && sub.unsubscribe();
}
}, [status]);
PS Правильно делать отписку в колбэке useEffect.