I'm trying to do a 6 digits verification code form (I know there is actually a package to do but I want it differently).
So I've done it like so:
const RegisterStep2 = (props) => {
const [digits, setDigits] = useState([]);
const textInputRefs = [];
const isNumeric = (str) => {
if (typeof str == 'number') return true;
if (typeof str != 'string') return false;
return !isNaN(str) && !isNaN(parseFloat(str));
};
handleForm = (index, value) => {
let digitsArray = digits;
let trueIndex = index;
for (let i = index - 1; i >= 0; i--) {
if (!isNumeric(digits[i])) {
trueIndex = i;
}
}
textInputRefs[trueIndex].focus();
index = trueIndex;
if (!isNumeric(digits[index])) {
if (value.key == 'Backspace' && textInputRefs[index - 1] != undefined) {
textInputRefs[index - 1].focus();
}
if (isNumeric(value.key)) {
digitsArray[index] = value.key;
} else {
}
} else {
if (value.key == 'Backspace') {
digitsArray[index] = '';
} else if (isNumeric(value.key)) {
digitsArray[index] = value.key;
}
}
setDigits(digitsArray);
if (isNumeric(digits[index]) && textInputRefs[index + 1]) {
textInputRefs[index + 1].focus();
} else if(index == textInputRefs.length) {
submitForm();
}
return (
...
<TextInput
ref={(input) => {
textInputRefs[1] = input;
}}
style={style.formDigit}
keyboardType={'numeric'}
maxLength={1}
underlineColorAndroid="transparent"
autoCapitalize="none"
value={digits[1]}
onKeyPress={({ nativeEvent }) => {
handleForm(1, nativeEvent);
}}
blurOnSubmit={false}
/>
... //The same input x3 times with corresponding index
<TextInput
ref={(input) => {
textInputRefs[5] = input;
}}
style={style.formDigit}
keyboardType={'numeric'}
maxLength={1}
underlineColorAndroid="transparent"
autoCapitalize="none"
value={digits[5]}
onKeyPress={({ nativeEvent }) => {
handleForm(5, nativeEvent);
}}
blurOnSubmit={false}
/>
...
);
Everything is working pretty well but the value of the input doesn't update in the way I want, when the user presses a key that is not handled by the handleForm (NaN), the input doesn't display what it that should (digits[index]
) but it displays the pressed key(not the value it is bind to).
digits value result as expected
Same for when the user is writing in a textInput that is not the first empty one, the input that should be written should be the first empty one:
So I wonder why the value that is displayed isn't the real state value, did I broke something, why the pipe between the state and the input seems broken. Even when the state gets updated (so the view is re-rendered), the input doesn't display his true value.