I am trying to get the Session Increment button to update the Session Length and the Timer, but the Timer always ends up lagging one update behind the Session Length.
This is the Session Length function:
const pressSession = (event) => {
if (event.target.id == 'session-increment') {
if (session < 60) setSession(parseInt(session)+1);
} else {
if (session > 1) setSession(parseInt(session)-1);
}
setTimer(session + ":00")
}
Why doesn’t setTimer(session + ":00") immediately update timer and re-render?
I ran into the same problem updating the display with the Calculator and refactored everything but I’m not sure why it started working. At that time I saw some explanations about asynchronous execution or a solution to use useEffect() with a dependency but nothing worked reliably. I’d really like to just understand this.
timer state is updated and reflects the current session value, immediately after any changes to the session state. This keeps the timer synchronized with the session length.
But I was already using ReactDOM to render the component to the HTML DIV, why did I need to add import ReactDOM from “https://esm.sh/react-dom”; when I started using useEffect?
Also, it works in codepen but I can’t get it to work in VSCode locally where I am working. It stops rendering when I add useEffect.
I added this:
import { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
With Vite follow the prompts to set up a React project and add your code to the App.jsx file or create components as needed.
Stackblitz or Codesandbox are much better than Codepen for React and they are as close to a local developer experience as you can get. I would suggest Stackblitz using the Vite React template.
The test script should work locally. Put it at the bottom of the HTML before the closing </body> tag, not in the head.
Using the React/Babel CDN links locally is not a good idea. They are only there so people can quickly try React and they are from before easy to set up build systems like Vite existed.
The https://esm.sh links act as modules you bring in and I’m not sure how well that plays with scripts marked with text/babel (which is for the JSX transform), the script has to be marked and used as a module for https://esm.sh to work.
I tried to port everything over to the Vite environment but it’s only partially working and opened up a new category of troubleshooting. Forego for now, but I’ll check it out later. I think I get it, Vite is setting up a local React server environment instead of trying to use those CDN imports?
The test script should work locally. Put it at the bottom of the HTML before the closing </body> tag, not in the head.
This was the problem, thanks!
For now, I’m going move forward with the project using this:
One last thing I don’t understand: Why doesn’t setTimer(session + ":00") immediately update timer and re-render?
Why do we need to use useEffect() ?
My understanding is that React will batch renders so it doesn’t update too often. It will update session but then not render timer until the next render, and that’s why it’s always behind. Is that correct?
Cool, I will keep this in mind! Don’t always need to use state.
In this case though, if you update doubleCountFixed independently it won’t render the change. Would you need to use useEffect dependency to re-render doubleCountFixed?
function incrementDoubleCountFixed() {
doubleCountFixed +=1;
}
return (
<>
<button onClick={increment}>count is {count}</button>
<button onClick={incrementDoubleCountFixed}>Add 1 to doubleCountFixed</button>
I also just noticed this warning in the console, locally:
Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot
createRoot: New method to create a root to render or unmount. Use it instead of ReactDOM.render. New features in React 18 don’t work without it. React DOM Client
yap…
If you’ve written React class components before, you should be familiar with lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount.
The useEffect Hook is all three of these lifecycle methods combined.
This gave me a much better perspective on what useEffect is. componentDidMount, componentDidUpdate, and componentWillUnmount are all very well named, useEffect is such a bizarre name it gives no insight into what it does! In any case, I got a much better understanding in the end, what more can you ask for.
That said, I did watch Landon Schlangen’s “Build a 25 + 5 clock” video to get some insight on this. He never uses useEffect and never seems to have a problem with asynchronous updates. That video is 3 years old though, and I think useEffect was introduced in 2019 so maybe people weren’t using it yet.