React无状态组件中createRef失效,调用focus报空值错误
问题分析与解决方案
你遇到的这个'Cannot read property "focus" of null'错误,核心原因是在函数组件里误用了createRef,而没有使用React为函数组件专门设计的useRef Hook,和父组件的Redux connect包装没有关系。
为什么会出错?
createRef是为类组件设计的,它的特性是每次组件重新渲染时都会生成一个全新的引用对象。而你的Card是函数组件,每次状态变化(比如切换编辑模式)都会重新执行整个组件函数,这时候inputText = createRef()会创建新的ref,导致当你调用inputText.current.focus()时,这个新的ref还没关联到真实的DOM元素,自然就是null。
而useRef Hook会在组件的整个生命周期内保持同一个引用对象,不管组件渲染多少次,它指向的都是同一个DOM节点(当ref被挂载后)。
修复后的代码
只需要把createRef替换成useRef,同时记得从React导入useRef:
import React, { useRef } from 'react'; // 替换原来的createRef为useRef import './Card.scss'; const Card = ({isEditing, item, onBlur, onChange}) => { const inputText = useRef(null); // 用useRef初始化,默认值设为null const editing = (editMode) => { if (editMode) { // 加可选链操作符,避免DOM未挂载时调用focus报错 inputText.current?.focus(); } return e => { e.stopPropagation(); isEditing(item, editMode); }; } const update = () => { return e => { onChange(item.id, e.target.value); } } return ( <div className="card"> <img className="card-image" src="https://picsum.photos/200/200" alt="no image display" /> <div className="card-body"> {item.edited ? ( <div> <input type="text" ref={inputText} onClick={e => e.stopPropagation()} value={item.name} onBlur={editing(false)} onChange={update()} /> </div> ) : ( <h3 className="card-title" onClick={editing(true)}> {item.name} </h3> )} </div> </div> ); } export default Card;
额外优化提示
- 我在调用
focus时加了可选链操作符?.,这样即使inputText.current还是null(比如DOM还没来得及挂载),也不会抛出错误,代码更健壮。 - 你的
update和editing函数每次渲染都会创建新的事件处理函数,后续可以用useCallback来优化性能,不过这不是导致当前错误的原因,属于可选优化。
内容的提问来源于stack exchange,提问作者Joseph Williams
相关产品推荐
相关产品推荐

