React官方教程跨组件DOM节点访问示例与实际运行不符的疑问
问题解析与解答
首先明确:教程的描述是正确的,你遇到的情况大概率是误运行了教程中已修正的示例,而非“默认情况”的错误代码。
核心原理
React中,ref是一个特殊属性,默认情况下:
- 对于DOM元素(如
<input>),ref会指向对应的DOM节点; - 对于未使用
React.forwardRef()包装的函数组件,ref不会被当作普通props传入组件内部,父组件传递的ref会得到null,同时控制台会弹出Function components cannot be given refs的警告。
你看到的“正常运行”的原因
你运行的沙箱/本地代码,要么是:
- 组件接收的是自定义命名的props(比如你示例中的
myCustomRef),而非ref这个特殊属性——此时它就是普通props,和其他props一样传递,自然能正常将ref绑定到内部输入框; - 组件已经用
React.forwardRef()做了包装,实现了ref的转发(这是跨组件传递ref的标准写法)。
代码对比验证
错误写法(符合教程“默认情况”)
import { useRef } from 'react'; function MyInput() { // 无法通过props获取到父组件传递的ref return ( <> <label>Name:</label> <input /> </> ); } export default function MyForm() { const inputRef = useRef(null); function handleClick() { inputRef.current.focus(); // 执行时会报错,因为current为null } return ( <> <MyInput ref={inputRef} /> <button onClick={handleClick}>Focus the input</button> </> ); }
运行这段代码,控制台会弹出警告,点击按钮会触发Cannot read properties of null (reading 'focus')错误。
正确写法1:自定义props传递ref(你的示例)
import { useRef } from "react"; function MyInput({myCustomRef}) { return ( <> <label>Name:</label> <input ref={myCustomRef} /> </> ); } export default function MyForm() { const inputRef = useRef(null); function handleClick() { inputRef.current.focus(); } return ( <> <MyInput myCustomRef={inputRef} /> <button onClick={handleClick}>Focus the input</button> </> ); }
这种写法可行,但属于“通过普通props传递ref对象”,不是利用ref属性的标准跨组件访问方式。
正确写法2:使用forwardRef(标准方案)
import { useRef, forwardRef } from 'react'; // 用forwardRef包装组件,接收props和ref参数 const MyInput = forwardRef((props, ref) => { return ( <> <label>Name:</label> <input ref={ref} /> </> ); }); export default function MyForm() { const inputRef = useRef(null); function handleClick() { inputRef.current.focus(); } return ( <> <MyInput ref={inputRef} /> <button onClick={handleClick}>Focus the input</button> </> ); }
这是React官方推荐的跨组件传递ref的方式,符合ref属性的设计意图。
总结
教程中关于“默认情况下给自定义函数组件加ref会得到null”的描述完全正确,你看到的正常运行的代码已经是教程后续给出的修正方案。如果要验证教程的“默认情况”,请运行上述的错误写法代码,就能看到对应的警告和报错。
内容的提问来源于stack exchange,提问作者nammae88
相关产品推荐
相关产品推荐

