Judoboy Alex
Judoboy Alex

Reputation: 350

Cursor jumps to the end, whenever value is changed in the input form

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

Answers (1)

Valentin
Valentin

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>
  );
};

Edit number-field-experiments-III-ts

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

Related Questions