React中为何不使用自定义含current属性的对象替代createRef?
createRef API? React文档中提到:
Refs通过
React.createRef()创建,并通过ref属性绑定到React元素
打印createRef生成的对象,会得到一个current属性为null的对象。出于好奇,我尝试用普通空对象(比如this.myRef = {})作为ref绑定到元素,结果居然可行,测试代码如下:
class CustomTextInput extends React.Component { constructor(props) { super(props); this.myRef = {}; // 居然能用!!! //console.log(React.createRef()); // 绑定方法 this.RefFocus = this.Myfocus.bind(this); } componentDidMount() { console.log(this.myRef.current); } Myfocus() { this.myRef.current.focus(); } render() { return ( <div> <input type="text" ref={this.myRef} /> <input type = "button" value = "Focus the text input" onClick = {this.RefFocus} /> </div> ); } } ReactDOM.render(<CustomTextInput />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="app"></div>
由此我产生疑问:我们究竟为何需要createRef这个API?React对它是否有特殊处理,比如性能或内存优化?是否存在像ref转发这类场景,普通{current: null}对象无法正常工作?
答案
1. 语义明确,提升代码可读性
createRef()是官方明确的创建React引用的方式,看到它就能立刻明白这个变量的用途是存储DOM元素或组件实例的引用。而普通对象可以被用来做任何事,其他开发者阅读代码时可能会疑惑这个对象是否还有别的功能,增加理解成本。
2. 避免意外修改风险
createRef创建的对象,其current属性的更新完全由React控制——只有在组件挂载、卸载或更新的合适时机,React才会修改它。如果用普通对象,你可能在代码的其他地方不小心修改current的值,导致ref失效,排查这类问题会很麻烦。
3. 兼容React高级特性
部分React高级特性依赖createRef生成的对象,比如ref转发(React.forwardRef)。当需要将父组件的ref传递到子组件内部的元素时,forwardRef会专门识别createRef创建的引用,确保传递逻辑正常运行。普通对象在简单场景下能用,但在复杂的组件嵌套、ref转发场景中可能出现异常。
另外,React后续版本可能会对createRef做针对性优化,比如内存泄漏防护、性能提升等,普通对象无法享受这些升级带来的好处。
4. 统一编码规范
团队开发时,统一使用createRef能保持代码风格一致,新人接手项目时也能更快理解代码逻辑。如果有人用普通对象、有人用createRef,代码会显得混乱,增加维护成本。
总结来说,简单场景下普通对象确实能临时替代,但从代码规范、可读性、兼容性和未来扩展性来看,官方推荐的createRef才是更稳妥的选择。
内容的提问来源于stack exchange,提问作者user31782

