One of the most bizzare things about programming to me is how developers go out of there way to avoid doing the very thing that programs are suppose to do: change state and create side-effects. I was reminded of this oddity once again with this tweet about JavaScript:

These two options were presented with the question, “which one is clearer?”
I think none of them, but let’s get into it before I go there.
React
The React code has less lines, but it has abstractions baked into it that obscure the example like useEffectEvent and useEffect.
export function App({ bpm }) {
const tick = useEffectEvent(() => {
console.log("BPM:", bpm);
});
useEffect(() => {
let id = setInterval(tick, bpm);
return () => clearInterval(id);
}, [bpm]);
return <div>{bpm}</div>;
}
Ok, great, those abstractions …
Remix
The Remix example also has abstractions like setupProps and the Remix.Handle
export function App(
this: Remix.Handle,
setupProps: { bpm: number }
) {
let bpm = setupProps.bpm;
let interval = 0;
const makeInterval = () => {
clearInterval(interval);
setInterval(() => {
if (this.signal.aborted) {
clearInterval(interval);
}
console.log("BPM:", bpm);
}, bpm);
};
makeInterval();
return (updateProps: { bpm: number }) => {
if (updateProps.bpm !== bpm) {
bpm = updateProps.bpm;
makeInterval();
}
return <div>{bpm}</div>;
};
}
It’s more lines of code, and many in the thread were commenting that they prefer this example because its clearer.
HTML and JavaScript
Let’s have a look at the most concrete example that will get ripped to shreds by any self-respecting JavaScript developer: a brittle, concrete implementation that directly manipulates the DOM.
<!DOCTYPE html>
<html>
<body>
<div id="bpm"></div>
<script>
let bpm = 70;
function tick() {
console.log("BPM:", bpm);
document.getElementById("bpm").textContent = bpm;
setTimeout(tick, bpm);
}
tick();
</script>
</body>
</html>
State changes and side-effects are OK
I’ve talked to Elm developers…