I have 3 input fields on my page. To fill in these inputs, it is not by what the user types, but by what the user presses on the <Keyboard /> component of the react-simple-keyboard library.
I'm managing to save what the user presses on the <Keyboard /> component. The problem is that I'm not able to separate the fields. For example, what I type in the 1st input is also going in the 2nd and 3rd input.
In <Keyboard /> we have a prop called onInit. I believe the problem is in how I am manipulating this prop. But I don't know how to fix this. Can you tell me what I'm doing wrong?
It's easier to understand with the codes and images below: Here's my code I put into codesandbox
import React, { useState } from "react";
import { CustomKeyboard } from "./components";
import { KeyboardEnum } from "./components/CustomKeyboard/KeyboardEnum";
import "./styles.css";
interface InputValuesProps {
field1: string;
field2: string;
field3: string;
}
export default function App() {
const [inputValue, setInputValue] = useState<string>("");
const [inputValues, setInputValues] = useState<InputValuesProps>({
field1: "",
field2: "",
field3: "",
});
const [activeInput, setActiveInput] =
useState<keyof InputValuesProps>("field1");
const onChange = (input: string) => {
setInputValues({ ...inputValues, [activeInput]: input });
setInputValue(input);
};
console.log("inputValues: ", inputValues);
const onInputFocus = (inputName: any) => {
setActiveInput(inputName);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<input
type="text"
value={inputValues.field1}
onClick={() => onInputFocus("field1")}
onChange={() => {}}
/>
<input
type="text"
value={inputValues.field2}
onClick={() => onInputFocus("field2")}
onChange={() => {}}
/>
<input
type="text"
value={inputValues.field3}
onClick={() => onInputFocus("field3")}
onChange={() => {}}
/>
<CustomKeyboard
startValue={inputValue}
keyboardOnChange={onChange}
layoutName={KeyboardEnum.Numbers}
maxCharacters={16}
/>
</div>
);
}
// CustomKeyboard component
import React, { useEffect, useInsertionEffect, useRef, useState } from "react";
import Keyboard from "react-simple-keyboard";
import { KeyboardEnum } from "./KeyboardEnum";
import "./index.css";
export interface CustomKeyboardProps {
startValue: string;
keyboardOnChange: (inputValue: string) => void;
layoutName:
| KeyboardEnum.Numbers
| KeyboardEnum.Alphabet
| KeyboardEnum.Symbols
| KeyboardEnum.Shift;
maxCharacters: number;
}
const CustomKeyboard = (props: CustomKeyboardProps) => {
const [layoutName, setLayoutName] = useState(props.layoutName);
const [inputValue, setInputValue] = useState(props.startValue);
const keyboardRef = useRef();
const handleShift = (button: string): void => {
switch (button) {
case "{enter}":
setInputValue("");
props.keyboardOnChange(inputValue);
break;
case "{shift}":
setLayoutName(
layoutName === KeyboardEnum.Alphabet
? KeyboardEnum.Shift
: KeyboardEnum.Alphabet
);
break;
case "{numbers}":
setLayoutName(KeyboardEnum.Numbers);
break;
case "{abc}":
setLayoutName(KeyboardEnum.Alphabet);
break;
case "{symbols}":
setLayoutName(KeyboardEnum.Symbols);
break;
default:
break;
}
};
const onKeyPress = (button: string): void => {
if (button === "{backspace}" && inputValue && inputValue.length === 1) {
setInputValue("");
}
if (
button === "{numbers}" ||
button === "{abc}" ||
button === "{shift}" ||
button === "{symbols}" ||
button === "{enter}"
)
handleShift(button);
};
const onChange = (input: string) => {
const _input = input.replace(/\D/g, "");
if (/^\d*$/.test(_input) && _input.length <= props.maxCharacters) {
setInputValue(_input);
if (keyboardRef.current) {
try {
// @ts-ignore
keyboardRef.current.setInput(_input);
} catch {
console.log("Keyboard error");
}
}
}
};
const customLayout = {
numbers: [
"1 2 3 4 5 6 7 8 9 0 {backspace}",
// eslint-disable-next-line quotes
"@ # $ % * ( ) ' \" {enter}",
// eslint-disable-next-line quotes
"{symbols} % - + = / ; : , . {symbols}",
"{abc} {space} {abc}",
],
shift: [
"Q W E R T Y U I O P {backspace}",
"A S D F G H J K L {enter}",
"{shift} Z X C V B N M ! ? {shift}",
"{numbers} , {space} . {numbers}",
],
symbols: [
"[ ] { } # % ^ * + = {backspace}",
"_ \\ | ~ < > € £ ¥ ·",
// eslint-disable-next-line quotes
"{numbers} . , ? ! ' {enter}",
"{abc} {space} {abc}",
],
abc: [
"q w e r t y u i o p {backspace}",
"a s d f g h j k l {enter}",
"{shift} z x c v b n m ! ? {shift}",
"{numbers} , {space} . {numbers}",
],
};
const customDisplay = {
"{numbers}": "123",
"{shift}": "⇧",
"{space}": "space",
"{backspace}": "⌫",
"{abc}": "ABC",
"{symbols}": "#+=",
};
useEffect(() => {
props.keyboardOnChange && props.keyboardOnChange(inputValue);
}, [inputValue]);
return (
<div className="bg-[#263238] flex h-[418px] justify-center items-center w-full shadow-2xl p-6 absolute bottom-0">
<div className="w-[1094px]">
<Keyboard
onInit={(e) => e.setInput(inputValue)}
keyboardRef={(r) => (keyboardRef.current = r)}
theme={"hg-theme-default myTheme1"}
onChange={onChange}
onKeyPress={onKeyPress}
layoutName={layoutName}
layout={customLayout}
display={customDisplay}
/>
</div>
</div>
);
};
export default CustomKeyboard;


When you change the focus, you need to update your input value:
Right now, the last input value is being carried over when the focus changes.
Additionally, you will need to update the
keyboardRef.currentwheneverprops.startValue. However, you will also need to take steps to ensure that you don't have circular updates on change.I think that your conjecture concerning
onInitis correct: theKeyboardcomponent is almost certainly not re-rendered/initialized each time you change yourstartValue.Without a MRE, it is hard to suggest further fixes.