So I'm a beginner to react, and I made this VERY simple project that takes someone's age via the "prompt()" function in JavaScript and passes it on to react to render it. You can click on the "Change Age" button to change the age being displayed on screen, meaning that it gives you another prompt by which you can re-enter the age and the new age will then be displayed on screen. Everything works fine, but because react keeps re-rendering my page, it shows the prompt multiple times. If you type any age in the prompts after the first one, the age doesn't change on screen. My guess is that this probably happens because the prompt appears before react's virtual dom has time to connect with the real dom, hence any value you enter in those prompts are completely ignored. This is probably some stupid little issue that I can't figure out on my own, any help is appreciated!
Here's App.js:
import {useState} from 'react';
function App() {
var ageInput = prompt("What Is Your Age?");
const [age, setAge] = useState(ageInput);
const changeAge = () => {
setAge(prompt("What Is Your Age?"));
}
return (
<div className="app">
<h1 style={{textAlign: "center"}}>Homepage</h1>
<p>Mario is {age} years old!</p>
<button onClick={changeAge}>Change Age</button>
</div>
)
}
export default App
Here's index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
PS: I do NOT know Redux yet, so any solutions involving Redux are out of my scope for now unfortunately
The problem is simply that this line: var ageInput = prompt("What Is Your Age?"); is at the "top level" of your function component, and therefore being called on each render. That means the prompt is shown - when you don't want it to be.
The top level of a React function component should be a "pure function" that reads the data it needs from props/state/etc and returns JSX representing your UI. Things with side effects, like "prompt", should be called from elsewhere - either from within an event handler like your changeAge (that part is absolutely fine in your code) - or from within a function passed to the useEffect hook.
And useEffect is what I'd recommend here. You seem to only want this prompt without a click first to set up the "initial state" of your component. So use useEffect with an empty array second parameter, to call changeAge also when the component first mounts, and not afterward. Your component will end up looking like this:
function App() {
const [age, setAge] = useState(0);
const changeAge = () => {
setAge(prompt("What Is Your Age?"));
}
useEffect(changeAge, []);
return (
<div className="app">
<h1 style={{textAlign: "center"}}>Homepage</h1>
<p>Mario is {age} years old!</p>
<button onClick={changeAge}>Change Age</button>
</div>
)
}
The only slight downside to this is that you need an "initial age" to pass to the useState, which runs before the useEffect function, which will therefore be shown in your initial UI before the user has responded to the prompt. I've put 0 above but you can put whatever you want - it likely doesn't really matter, and if it does you can get the UI to display something slightly different up until age holds a sensible value.