React中styled-components包裹的input输入框按键后失焦如何解决
问题根因
输入框每次输入单个字符就失焦,核心原因是你将styled-components生成的FormControl组件定义写在了CourseInput函数组件的内部。
当输入内容触发state更新时,CourseInput会重新执行渲染,每一次渲染都会创建一个全新的FormControl组件。React在diff时会判定新旧FormControl不是同一个组件,直接卸载旧组件、挂载新组件,旧组件内部的input会被直接销毁,新挂载的input默认没有焦点,就出现了按一次键就失焦的现象。
除此之外你的代码还有4处会导致功能/样式异常的问题:
- 两处样式插值里把
props拼写为porps,会导致invalid状态的样式读取失败 - input的
background样式规则末尾缺少分号,会导致后续样式解析失效 - input没有绑定
value属性,不是标准的受控组件,极端场景会出现状态和输入值不同步的问题 - 你给input加的固定
key无法解决失焦问题:父组件FormControl已经被判定为新节点,内部所有子元素都会被重新挂载,给子元素加key不生效。
修复步骤
- 将
FormControl的定义移动到CourseInput函数组件的外部,保证组件只在文件初始化时创建一次,重渲染时不会被识别为新组件 - 修正
porps的拼写错误,补全缺失的样式分号 - 给input绑定
value属性对应enteredValue状态,移除input上多余的固定key
修复后完整代码
import React, { useState } from 'react'; import styled from 'styled-components'; import Button from '../../UI/Button/Button'; import './CourseInput.css'; // styled组件移到函数组件外部定义,避免重渲染时重新创建 const FormControl = styled.div` margin: 0.5rem 0; & label { font-weight: bold; display: block; margin-bottom: 0.5rem; color: ${props => props.invalid ? 'red' : 'black'}; } & input { display: block; width: 100%; border: 1px solid ${props => (props.invalid ? 'red' : '#ccc')}; background: ${props => props.invalid ? '#ffd7d7' : 'transparent'}; font: inherit; line-height: 1.5rem; padding: 0 0.25rem; } & input:focus { outline: none; background: #fad0ec; border-color: #8b005d; } `; const CourseInput = props => { const [enteredValue, setEnteredValue] = useState(''); const [isValid, setIsValid] = useState(true); const goalInputChangeHandler = event => { if (event.target.value.length > 0) { setIsValid(true); } setEnteredValue(event.target.value); }; const formSubmitHandler = event => { event.preventDefault(); if (enteredValue.trim().length === 0) { setIsValid(false); return; } props.onAddGoal(enteredValue); }; return ( <form onSubmit={formSubmitHandler}> <FormControl invalid={!isValid}> <label>Course Goal</label> <input type='text' value={enteredValue} onChange={goalInputChangeHandler} /> </FormControl> <Button type="submit">Add Goal</Button> </form> ); }; export default CourseInput;
内容的提问来源于stack exchange,提问作者Narayan Poudel
相关产品推荐
相关产品推荐

