Reputation: 350
Whenever I place the cursor in the middle of numbers, let's say 3|3000
then press either backspace or delete, cursor jumps to the back. I believe this is happening because I have value
set as displayValue
and since displayValue
is a state, whenever displayValue
changes value, input re-renders and therefore cursor moves back. I know simple solution is to set value={value}
, but for this particular input I need to use state displayValue
instead so I need to use alternative solution. Is there a way to cursor to remain in its natural position even through re-rendering? https://codesandbox.io/s/number-field-experiments-iii-ts-nh95up?file=/src/App.tsx:0-1633
import React, { useState, useRef, useEffect } from "react";
import "./styles.css";
export interface NumberFieldInterface {
onChange?: (value: number) => void;
value: number;
}
const NumberField: React.FC<NumberFieldInterface> = ({ value, onChange }) => {
const inputRef = useRef(null);
const [displayValue, setDisplayValue] = useState("");
const onChangeValue = (value: any) => {
if (typeof onChange === "function") {
onChange(value);
}
};
useEffect(() => {
const newFormatValue = value.toString();
setDisplayValue(newFormatValue);
}, [value]);
return (
<div>
<input
type="text"
ref={inputRef}
value={displayValue}
onChange={(e: React.FormEvent<HTMLInputElement>) =>
onChangeValue(e.target.value)
}
/>
</div>
);
};
export default function App() {
const [inputValue, setInputValue] = useState<number>(0);
const handleChange = (val: number) => {
setInputValue(val);
};
return (
<div className="App">
<NumberField value={inputValue} onChange={handleChange} />
</div>
);
}
Upvotes: 0
Views: 753
Reputation: 11812
Instead of using useEffect
to change your displayValue
, how about doing it inside the onChange
?
const NumberField: React.FC<NumberFieldInterface> = ({ value, onChange }) => {
const inputRef = useRef(null);
const [displayValue, setDisplayValue] = useState("");
const onChangeValue = (value: any) => {
if (typeof onChange === "function") {
onChange(value);
}
const newFormatValue = value.toString();
setDisplayValue(newFormatValue);
};
return (
<div>
<input
type="text"
ref={inputRef}
value={displayValue}
onChange={(e: React.FormEvent<HTMLInputElement>) =>
onChangeValue(e.target.value)
}
/>
</div>
);
};
It seems to fix the issue of jumping around but I’m not entirely sure it fixes everything. And I’m unsure why value
is passed to the component but never used.
Upvotes: 1