In React, I want that if something is typed into a form, another form is immediately set to focus.
For example:
<html>
<head>
<title>React App</title>
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
</head>
<body>
<div id="mydiv"></div>
<script type="text/babel">
//Now its basically like React
function Inputs() {
const [otp, setOtp] = React.useState([]); //Here are stored the Values of the numbers
const itemsRef = React.useRef([]); //Here are stored the refs of the numbers
const setOtpfunction = (e, i) => {
const key = parseInt(e.key); //I first parse the key that i got from onKeyPress to a number
if (key) {
let OTP = [...otp];
OTP[i] = key;
setOtp(OTP); //Then i update the numbers
if (i < 5) {
const nextForm = i 1; //Here i say that the next item schould be the item with the index 1
ref[i].focus(); //And here i set the focus. ref.current.focus() wouldnt work in this case
}
}
};
return (
<div className="space-x-2">
<input
placeholder="first input"
type="number"
className="otpNumber"
onChange={(e) => (e = null)} //that there is no error because there is no onChange function
required
onKeyPress={(e) => setOtpfunction(e, 0)}
ref={(ref) => (itemsRef[0] = ref)}
autoFocus
value={otp[0] || ""}
/>
<input
placeholder="second input"
type="number"
className="otpNumber"
onChange={(e) => (e = null)} //that there is no error because there is no onChange function
onKeyPress={(e) => setOtpfunction(e, 1)}
ref={(ref) => (itemsRef[1] = ref)}
value={otp[1] || ""}
/>
<input
placeholder="third input"
type="number"
className="otpNumber"
onChange={(e) => (e = null)} //that there is no error because there is no onChange function
onKeyPress={(e) => setOtpfunction(e, 2)}
ref={(ref) => (itemsRef[2] = ref)}
value={otp[2] || ""}
/>
<p>Now you can type in 1 number in the inputs and they are stored in UseState. But i want that if in the first input, one number is entered, it focuses the second input and so on</p>
</div>
);
}
class Render extends React.Component {
render() {
return (
<div>
<Inputs />
</div>
);
}
}
ReactDOM.render(<Render />, document.getElementById("mydiv"));
</script>
</body>
</html>
The console's error was only a warning that you should compile your scripts for production. That's why I hid it.
I also tested it with document.getElemntbyId, which also didn´t work.
I hope you can understand what I mean. Thanks for any answers that can be provided!
CodePudding user response:
I would rather make a single Input
component, that notifies the parent when the user types something and updates the state accordingly:
const OTP_LENGTH = 4;
export default function OTPForm() {
const [index, setIndex] = useState(0);
function done() {
if (index === OTP_LENGTH - 1) {
console.log("All inputs filled");
return;
}
setIndex(index 1);
}
return (
<form>
{Array.from({ length: OTP_LENGTH }, (_, i) => (
<Input key={i} isCurrent={i === index} done={done} />
))}
</form>
);
}
function Input({ isCurrent, done }) {
const ref = useRef(null);
useEffect(() => {
if (isCurrent && ref.current) {
ref.current.focus();
}
}, [isCurrent]);
function onInput(event) {
if (event.target.value > 1) {
event.preventDefault();
return;
}
if (event.target.value === 1) {
done();
}
}
return <input ref={ref} onInput={onInput} type="number"/>;
}
Up to you to expose proper onError
/ onSubmit
handlers from the parent component.