React类组件中selectNode属性为undefined的原因排查
问题原因及解决方法
问题描述
我写了一个React类组件,通过ref把select元素绑定到实例的selectNode属性,但打印这个属性时显示undefined,想知道其中的原因。
代码示例
import React, { Component } from 'react' const add='add' const sub='sub' const oddAdd='oddAdd' const AsynAdd='AsynAdd' export default class Count extends Component { state={count:0} increase=(add)=>{ console.log(this,this.selectNode,this.state) return (e)=>{ console.log('after',this,this.selectNode) const{value}=this.selectNode const {count}=this.state this.setState({count:count+value*1}) } } decrease=()=>{ const{value}=this.selectNode const {count}=this.state this.setState({count:count-value*1}) } increaseOdd=()=>{ const{value}=this.selectNode const {count}=this.state if(count%2!==0) this.setState({count:count+value*1}) } AsynIncrease=()=>{ setTimeout(()=>{const{value}=this.selectNode const {count}=this.state this.setState({count:count+value*1})},1000) } render() { return ( <div> <h1>Total sum is {this.state.count}</h1> <select ref={c=>this.selectNode=c}> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button onClick={this.increase(add)}>increase</button> <button onClick={this.decrease}>decrease</button> <button onClick={this.increaseOdd}>increase when odd</button> <button onClick={this.AsynIncrease}>asynchronize increase</button> </div> ) } }
原因分析
你看到的this.selectNode为undefined是组件渲染阶段的打印结果:
- 当组件执行
render()方法时,<button onClick={this.increase(add)}>会立即调用this.increase(add)函数,此时组件的DOM还没完成挂载,ref的回调函数c=>this.selectNode=c还没被执行,所以this.selectNode还没被赋值,自然是undefined。 - 而点击按钮后,
increase返回的箭头函数执行时,组件已经完成挂载,ref已经绑定到DOM元素,所以此时打印的this.selectNode是有值的。
解决建议
如果你不想在渲染阶段就执行increase函数(避免不必要的执行和undefined打印),可以修改事件绑定方式:
- 保持
increase的柯里化写法,此时渲染时执行increase(add)只是返回一个函数,不会触发内部逻辑,只有点击按钮时才会执行:
increase = (add) => (e) => { console.log(this, this.selectNode) const { value } = this.selectNode const { count } = this.state this.setState({ count: count + value * 1 }) }
绑定方式不变:<button onClick={this.increase(add)}>increase</button>
- 如果你不需要传递
add参数(代码里该参数未被使用),可以直接把increase改成普通事件处理函数:
increase = (e) => { console.log(this, this.selectNode) const { value } = this.selectNode const { count } = this.state this.setState({ count: count + value * 1 }) }
绑定方式改为:<button onClick={this.increase}>increase</button>
另外,类组件中也可以使用createRef()来创建ref,写法更直观:
import React, { Component, createRef } from 'react' export default class Count extends Component { selectNode = createRef() // ...其他代码 render() { return ( <div> {/* ... */} <select ref={this.selectNode}> {/* ... */} </select> {/* 使用时通过this.selectNode.current获取DOM元素 */} </div> ) } }
内容的提问来源于stack exchange,提问作者River Moon
相关产品推荐
相关产品推荐

