关于React 16.3 Ref API使用的两个技术疑问
嘿,咱们来一步步拆解你的问题,顺便先修正下代码里的小问题,这样更容易理解:
问题1:子组件中为何能使用this.lastref?和单向数据流有关吗?
首先得明确:你的子组件Cppersons里其实不能直接用this.lastref——因为这个lastref是父组件Cpersons创建的,子组件本身并没有定义这个属性,直接调用会报错。你可能是把ref的指向逻辑搞混了,我来理清楚:
父组件里的
this.lastref = React.createRef()创建了一个ref对象,然后通过ref={this.lastref}绑定到子组件<Person />上,这意味着父组件的lastref.current会指向子组件的实例。所以父组件能通过this.lastref.current调用子组件的方法(比如myFocus),这是父组件获取子组件实例的方式,但反过来,子组件不能直接拿到父组件的lastref,除非父组件主动通过props把它传过去(但这完全没必要,也不符合React的设计思路)。这和单向数据流没关系:单向数据流是指数据通过props从父组件流向子组件,而ref是用来获取组件/ DOM元素实例的工具,不属于“数据流”的范畴,它是一种直接操作实例的手段。
如果你的子组件myFocus方法是想聚焦某个内部元素(比如input),正确的做法是在子组件内部创建自己的ref,指向要操作的DOM元素,就像这样:
// 子组件 person-s.js class Cppersons extends Component { // 子组件自己的ref,指向内部的input inputRef = React.createRef(); myFocus () { // 这里操作的是子组件自己的ref this.inputRef.current.focus(); } render() { return ( <div> <input ref={this.inputRef} type="text" placeholder="我会被聚焦" /> </div> ); } }
问题2:myFocus是静态方法吗?需要初始化吗?
myFocus不是静态方法!静态方法是用static关键字定义的,属于类本身(比如static myFocus() {}),不能访问实例的属性(比如this.inputRef)。而你定义的myFocus是实例方法,属于子组件的每个实例,能访问实例上的属性和方法。
这种实例方法不需要额外初始化,不过要注意this的指向:当父组件通过this.lastref.current.myFocus()调用时,myFocus里的this会自动绑定到子组件的实例(因为current就是子组件实例,调用它的方法时this默认指向实例),所以你不需要额外做绑定操作。
补充:修正父组件的代码错误
你的父组件代码有几个语法问题,我帮你改过来:
// 父组件 person.js import React, { Component } from 'react'; import Person from './persons/person-s'; class Cpersons extends Component { // 用类字段语法创建ref(不需要写constructor) lastref = React.createRef(); componentDidMount() { // 调用子组件的myFocus方法 this.lastref.current.myFocus(); } render() { // 补全列表遍历逻辑 return this.props.persons.map((el, index) => ( <Person key={el.id} click={() => this.props.cpdelete(index)} // 避免bind在render里重复创建函数 ref={this.lastref} name={el.name} age={el.age} changed={(event) => this.props.cpchanged(event, el.id)} /> )); } } export default Cpersons;
这样整个流程就通顺了:父组件挂载后,通过ref获取子组件实例,调用子组件的myFocus方法,子组件通过自己的ref找到内部input并聚焦。
内容的提问来源于stack exchange,提问作者user9726696

