[英]Caret Jumping to End When Rejecting Input
我有一個值的輸入。 我想驗證用戶輸入的新值,並防止該值在無效時出現在輸入中。 例如,值應該是數字,因此只能包含數字、點和逗號。
我有一個驗證 function 根據值是否符合標准(按預期工作)返回true
/ false
:
function validateInput(input) {
let allow = true
const splitValuesByDecimal = input.split(',')
if(allow) allow = /^[\d|,|.]*?$/.test(input) // allow only digits, dots, and commas
if(allow) allow = splitValuesByDecimal.length <= 2 // allow only 1 decimal separator (comma)
if(allow && splitValuesByDecimal.length > 1) allow = splitValuesByDecimal.at(-1).length <= 2 // allow only maximum of 2 decimal characters
return allow
}
在我的輸入字段中,我調用了一個自定義的handleChange
function,它確保新輸入在存儲到 state 變量之前是有效的。
渲染輸入
<input value={inputVal} onChange={handleChange} />
處理輸入變化
function handleChange(e) {
const value = e.target.value
if(validateInput(value)) {
setInputVal(value)
}
}
如果插入了無效輸入並且驗證失敗,則我的輸入字段中的值不會更改(如預期的那樣),但插入符號會跳轉到輸入字段的末尾(不可取)。
嘗試的解決方案
我試圖通過采用這個答案來修復插入符號跳躍行為,其中我創建了一個cursor
state 變量,該變量跟蹤預期的插入符號 position:
function MyComponent() {
const [inputVal, setInputVal] = useState('')
const [cursor, setCursor] = useState(null)
const inputRef = useRef()
useEffect(() => {
if (inputRef.current) inputRef.current.setSelectionRange(cursor, cursor);
}, [inputRef, cursor, inputVal])
function validateInput(input) {
...
}
function handleChange(e) {
const value = e.target.value
if(validateInput(value)) {
setCursor(e.target.selectionStart)
setInputVal(value)
}
else {
setCursor(e.target.selectionStart - 1)
}
}
return (
<input
ref={inputRef}
value={inputVal}
onChange={handleChange} />
)
}
使用此解決方案,插入符號在第一次輸入無效值時保持在正確的 position 處,但隨着我繼續按下相同的鍵,一遍又一遍地插入無效值,在第一次之后,插入符號移回末尾的輸入。 這是因為 useEffect 沒有被調用第二次和后續的時間。
無論用戶嘗試插入無效值多少次,我如何才能使插入符號始終保持在相同的 position 上?
更新:-
對不起,我的不好,我沒有完全看這個問題。 但是,我所說的也是正確的,但在當前情況下並非如此。 請在下面找到更新的代碼。 下面的代碼也應該更高效,因為它不涉及每次更改的重新渲染
import React, { useState, useRef } from 'react';
export function App(props) {
const inputRef = useRef()
const oldVal = useRef(null)
function validateInput(input) {
let allow = true
const splitValuesByDecimal = input.split(',')
if(allow) allow = /^[\d|,|.]*?$/.test(input) // allow only digits, dots, and commas
if(allow) allow = splitValuesByDecimal.length <= 2 // allow only 1 decimal separator (comma)
if(allow && splitValuesByDecimal.length > 1) allow = splitValuesByDecimal.at(-1).length <= 2 // allow only maximum of 2 decimal characters
console.log(allow)
return allow
}
function handleChange(e) {
const valueNew = e.target.value
const pos = e.target.selectionStart - 1
if(validateInput(valueNew)) {
oldVal.current = valueNew
} else {
inputRef.current.value = oldVal.current
inputRef.current.setSelectionRange(pos, pos)
}
}
return (
<div key='mydiv' className='App'>
<input key='MyFixedKeyValue' ref={inputRef} onChange={handleChange} />
</div>
);
}
我也在播放代碼代碼鏈接上進行了相同的更改
React 在 setstate 調用時重新渲染整個組件。 在您的情況下,值將被保留,因為它是受控輸入。 但在幕后 React 基本上是在每次輸入值時創建一個新的輸入字段。 強制做出反應以使用具有恆定值的相同字段傳遞鍵道具。
<input
key='MyFixedKeyValue'
ref={inputRef}
value={inputVal}
onChange={handleChange} />
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.