跳到主要内容

input

2023年07月18日
柏拉文
越努力,越幸运

一、认识


浏览器内置的 <input> 组件 允许你渲染不同类型的表单输入框。

二、语法


2.1 受控

export default function App() {
const [v,setV] = useState("");
return <input value={v} onChange={(e)=> setV(e.target.value)}></input>
}

2.2 非受控

export default function App() {
const ref = useRef("");

const handleChange = (e)=>{
console.log(e.target.value)
}
return <input defaultValue={ref.current} onChange={handleChange}></input>;
}

三、属性


四、事件


五、实践


5.1 状态自治

当你使用受控输入框时,每次按键都会设置 state。如果包含 state 的组件重新渲染了大型树形结构,这可能会变得很慢。因此, 可以将 Input 的状态自我管理, 这样可以显著提高性能

import { useState } from "react";

function Input() {
const [text, setText] = useState("");
return <input value={text} onChange={(e) => setText(e.target.value)}></input>;
}

export default function App() {
console.log("渲染");
return (
<>
<Input />
<div>无关部分</div>
</>
);
}

5.2 中文输入

问题描述:

在使用 React 绑定 input 输入框的 onChange 方法时,如果使用中文输入法(或者其他输入法),会出现一个问题:还在输入拼音的时候,onChange 方法已经触发了,如下,即输入过程就已经触发了多次 onChange 方法。如果 onChange 方法有较为复杂的逻辑,就可能会带来一些用户体验或者逻辑的问题。

解决方案:

通过使用 compositionEvent 事件控制中文输入标识, 根据中文输入标识决定是否触发 onChange 。具体为: 通过监听输入法开始输入到结束的事件,即是去监听compositionstartcompositionend方法,通过设置一个变量,在两个方法里面设置 true/false,来判断是否处在中文输入拼音这个过程当中,如果是,则不触发 onChange 后续事件。

兼容处理:

  • 谷歌浏览器: compositionstart -> onChange -> compositionend, onChange 事件先于 compositionend 事件触发, 因此我们需要针对谷歌浏览器的 compositionend 结束后手动调用 onChange 处理函数。

  • 其他浏览器: compositionstart -> compositionend -> onChange

具体实现

import { useState } from 'react';
import {Input} from './components/Input/input';

function App() {
const [value, setValue] = useState('');
const [error,setError] = useState('');

const handleInputOnChange = (e: string, len: number) => {
setValue(e);
if(len >= 20){
setError("xx 超过20个字符");
}
};

const handleInputOnBlur = () => {
if(value.length === 0){
setError("请输入xx");
}
}

return (
<div style={{width: '300px'}}>
<Input
limit={20}
value={value}
error={error}
limitType="character"
onBlur={handleInputOnBlur}
onChange={handleInputOnChange}
/>
</div>
);
}

export default App;

六、故障


6.1 文本框未更新

6.2 输入框光标跳到开头

原因一、必须同步更新为 e.target.value

// 错误行为

function Input() {
const [text, setText] = useState("");
return <input value={text} onChange={(e) => setTimeout(()=>{setText(e.target.value)})}></input>;
}


// 正确行为

function Input() {
const [text, setText] = useState("");
return <input value={text} onChange={(e) => setText(e.target.value)}></input>;
}

原因二、更新的值为 e.target.value 以外的值

如果你想要控制输入框,你应该在 onChange 期间将对应的 state 变量更新为来自 DOM 的输入框的值。也就是说, 只可以更新为 e.target.value , 不可以更新为其他值。

// 错误行为

function Input() {
const [text, setText] = useState("");
return <input value={text} onChange={(e) => setText(e.target.value.toLocaleLowerCase())}></input>;
}

// 正确行为

function Input() {
const [text, setText] = useState("");
return <input value={text} onChange={(e) => setText(e.target.value)}></input>;
}

原因三、每次输入时, 输入框都会从 DOM 中删除并重新添加