I am new to react state hook. Here is the sample code:
import React, { useState, useEffect } from 'react';
export function App(props) {
const [c, setC] = useState(0);
const [b1, setB1] = useState(null);
useEffect(() => {
setC(1);
let b1 = document.getElementById("b1");
b1.addEventListener("click", f1);
setB1(b1);
}, []);
const f1 = () => {
console.log(c);
}
return (
<div className='App'>
<h1>Hello React.</h1>
<h2>Start editing to see some magic happen!</h2>
<button id="b1" />
</div>
);
}
// Log to console
console.log('Hello console')
If I click the button. The console always output 0 instead of 1 where i set the value in useEffect.
Please let me know what's wrong here. Looks like when I add eventlistener on the button, it remembers the C value instead of reading the C value from state every time.
At the time that the click listener is attached, the render that the state value closes over is that when the useEffect
callback was declared - which is when c
was still the prior value from back then. While you could fix it by logging c + 1
, a much better approach would be to avoid vanilla DOM methods entirely in React, and do it the React way instead, with a JSX onClick
prop on the button.
const App = () => {
const [c, setC] = React.useState(0);
React.useEffect(() => {
setC(1);
}, []);
const f1 = () => {
console.log(c);
}
return (
<div className='App'>
<h1>Hello React.</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={f1}>click</button>
</div>
);
}
ReactDOM.createRoot(document.querySelector('.react')).render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div class='react'></div>