react的受控组件和非受控组件 react受控和不受控组件的区别
论文深入探讨React中输入框在每次切换后失焦的常见问题。当输入框的值属性直接绑定到间歇更新的组件状态时,会导致不必要的组件重渲染,进而引发失焦。教程将详细解释这一现象的原因,并提供的解决方案,包括分离输入框的本地状态管理以及全局数据源的优化新策略,保证用户输入体验的流畅性。问题剖析:React受控输入失焦的深刻原因
在react中,当我们将表单元素(如、框)的value属性绑定到组件状态,通过并onchange事件处理器更新该状态时,我们称之为“受控组件”。这种模式保证了表单数据始终由react状态然而,不当的受控组件实现方式可能会导致一些类似的问题,其中最常见的就是输入框在每次按钮后失焦。
原始代码中存在的核心问题是,输入框的值属性直接来源于props.Freight,而props.Freight又直接映射到父组件的da taSource状态。当用户在输入框输入一个字符时,handleOnchange函数被调用,它会立即更新dataSource状态。setDataSource的调用会导致持有dataSource的父组件重新渲染,进而导致其子组件,即gridTemplate,也需要重新渲染。// 父组件中的状态与处理函数示例// const [dataSource, setDataSource] = useStatelt;anygt;(data);// const handleOnchange = (event:any, props:any) =gt; {// const newData = [...dataSource];// const itemIndex = newData.findIndex(// (item) =gt; item.OrderID === props.OrderID// );// newData[itemIndex].Freight = event.target.value;// setDataSource(newData); // 进程步骤都更新dataSource,导致父组件重渲染// };// 自定义网格组件(子组件)const gridTemplate = (props:any) =gt; { const val = props.Freight; // val直接来源于父组件的props return ( lt;divgt; lt;input value={val} onChange={(event) =gt;handleOnchange(event, props)} /gt; lt;/divgt; );};登录后复制
每次setDataSource触发重渲染时,React会重新执行gridTemplate函数,并根据新的props.Freight值重新渲染输入元素。
尽管React的协调(reconciliation)算法需要复用DOM元素,但在这种情况下,由于输入的值属性在每次渲染时都可能发生变化,并且整个组件树(从父组件到gridTemplate)都在重新构建,React可能会需要认为重新挂载(重新挂载)输入元素,或者在重新应用属性时导致资源丢失。用户在输入框的连续输入体验。解决方案:分离输入框的本地状态管理
解决此问题的关键在于,让输入框在用户输入过程中拥有自己的“瞬时”本地状态,而不是每次按下都立即同步到全局或父组件的状态。只有当用户完成输入(例如,通过防抖焦事件onBlur)或者通过防抖焦(debounce)机制时,才将这个最终值同步回父组件或全局数据源。
以下是修改后的gridTemplate组件,其内部维护了输入框的本地状态:import React, { useState, useEffect } from 'react';// 自定义网格组件(子组件)const gridTemplate = (props: any) =gt; { // 使用useState管理输入框的本地值 const [inputValue, setInputValue] = useState(props.Freight); //当props.Freight从父组件更新时,同步本地inputValue // 这很重要,以确保外部数据源更新时,输入框能反映最新值 useEffect(() =gt; { setInputValue(props.Freight); }, [props.Freight]); // 处理输入状态框的onChange事件,仅更新本地状态框 const handleInputChange = (event: React.ChangeEventlt;HTMLInputElementgt;) =gt; { setInputValue(event.target.value); }; // 处理输入框的onBlur事件,此时才将本地值同步回父组件 const handleInputBlur = () =gt; { // 假设更新父组件提供一个特定项的函数,例如 props.updateItemFreight // 该函数会负责更新父组件的数据源状态 if (props.updateItemFreight) { props.updateItemFreight(props.OrderID, inputValue); } }; return ( lt;divgt; lt;input value={inputValue} // 绑定到本地状态 onChange={handleInputChange} // 只需更新本地状态 onBlur={handleInputBlur} // 失焦时才同步到父组件/全局状态 /gt; lt;/divgt; );};// 假设父组件的最简单示例:// function ParentComponent() {// const [dataSource, setDataSource] = useStatelt;anygt;(/* 原始数据 */);// const更新商品运费 = (orderId: string, newFreight: string) =gt; {// setDataSource(prevData =gt; {// const newData = [...prevData];// const itemIndex = newData.findIndex(item =gt; item.OrderID === orderId);// if (itemIndex gt; -1) {// ne
wData[itemIndex].Freight = newFreight;// }// return newData;// });// };// return (// lt;divgt;// {dataSource.map((item: any) =gt; (// lt;gridTemplate// key={item.OrderID} // 保证有唯一的key// OrderID={item.OrderID}// Freight={item.Freight}// updateItemFreight={updateItemFreight} // 确定更新函数// /gt;// ))}// lt;/divgt;// );// }登录后复制
代码解释:useState(props.Freight):在gridTemplate组件内部,我们引入了一个新的状态变量inputValue,并将其初始值设置为props.Freight。这个inputValue将专门用于控制当前输入框的显示值。useEffect(() =gt; { setInputValue(props.Freight); }, [props.Freight]);:这是useEffect钩子的一个关键。它确保当父组件的props.Freight发生外部变化时(例如,数据从服务器更新或者父组件的其他操作改变了dataSource),inputValue能够及时同步,从而避免数据混乱。handleInputChange:当用户输入框中输入字符时,onChange事件触发handleInputChange。此函数只需更新inputValue这个本地状态,而不会立即更新父组件的数据源。由于只了子组件的本地状态,父组件不会重渲染,input元素也能保持焦点。handleInputBlur: 只有当输入框失去焦点时(例如,用户点击了其他位置或按下了Tab键),onBlur事件才会触发handleInputBlur。此时,我们将最终的inputValue传递给父组件提供的更新函数(例如props.updateItemFreight),由父组件来更新其数据源状态。这样,父组件的重渲染只发生在用户完成输入之后,而不是下次。注意事项与最佳实践理解状态管理的程度:区分组件内部的瞬时UI状态(如输入框的当前值)与全局或父组件需要持久化的数据状态。将UI状态本地化可以显着提升交互性能和用户体验。提升用户体验:避免输入框丢失焦不仅仅是技术问题,更是用户体验问题。一个流畅、响应迅速的输入界面能够极大提升用户满意度。性能考量:减少不必要的组件重渲染是React性能优化的方面。通过将状态更新推迟到必要时才进行,可以有效降低渲染负载。防抖(Debounce)与节流(Throttle): 如果您需要在用户输入过程中实时更新父组件或进行一些运行操作(如搜索建议),但又不想每次按键都触发,可以考虑使用防抖(Debounce)或节流(Throttle)技术。
这两种技术可以与本地状态结合使用,在onChange中更新本地状态
以上就是React文章受控组件:输入避免框失焦的常见陷阱与最佳实践的详细,更多请关注乐哥常识内容网其他相关!