React: “ this”在组件函数中是未定义的

class PlayerControls extends React.Component {
constructor(props) {
super(props)


this.state = {
loopActive: false,
shuffleActive: false,
}
}


render() {
var shuffleClassName = this.state.toggleActive ? "player-control-icon active" : "player-control-icon"


return (
<div className="player-controls">
<FontAwesome
className="player-control-icon"
name='refresh'
onClick={this.onToggleLoop}
spin={this.state.loopActive}
/>
<FontAwesome
className={shuffleClassName}
name='random'
onClick={this.onToggleShuffle}
/>
</div>
);
}


onToggleLoop(event) {
// "this is undefined??" <--- here
this.setState({loopActive: !this.state.loopActive})
this.props.onToggleLoop()
}

我想在切换时更新 loopActive状态,但是在处理程序中没有定义 this对象。根据教程文档,我 this应该参考组件。我错过了什么吗?

162171 次浏览

有几种方法。

一个是添加 this.onToggleLoop = this.onToggleLoop.bind(this);在构造函数中。< / p > 另一个是箭头函数 onToggleLoop = (event) => {...}。< / p >

然后还有onClick={this.onToggleLoop.bind(this)}

ES6 React.Component不会自动将方法绑定到自身。你需要自己在constructor中绑定它们。是这样的:

constructor (props){
super(props);
  

this.state = {
loopActive: false,
shuffleActive: false,
};
  

this.onToggleLoop = this.onToggleLoop.bind(this);


}

我在一个渲染函数中遇到了类似的绑定,并以以下方式传递this的上下文:

{someList.map(function(listItem) {
// your code
}, this)}

我还用过:

{someList.map((listItem, index) =>
<div onClick={this.someFunction.bind(this, listItem)} />
)}

如果你在componentDidMount等生命周期方法中调用您创建的方法…那么你只能使用this.onToggleLoop = this.onToogleLoop.bind(this)和胖箭头函数onToggleLoop = (event) => {...}

在构造函数中声明函数的正常方法不起作用,因为生命周期方法在前面被调用。

这样写你的函数:

onToggleLoop = (event) => {
this.setState({loopActive: !this.state.loopActive})
this.props.onToggleLoop()
}

Fat Arrow Functions .

关键字this在胖箭头函数内外的绑定是一样的。这与使用function声明的函数不同,后者可以在调用时将This绑定到另一个对象。维护this绑定对于像映射:this.items这样的操作非常方便。map(x => this.doSomethingWith(x))。

如果你正在使用babel,你使用ES7绑定操作符绑定'this' https://babeljs.io/docs/en/babel-plugin-transform-function-bind#auto-self-binding < / p >
export default class SignupPage extends React.Component {
constructor(props) {
super(props);
}


handleSubmit(e) {
e.preventDefault();


const data = {
email: this.refs.email.value,
}
}


render() {


const {errors} = this.props;


return (
<div className="view-container registrations new">
<main>
<form id="sign_up_form" onSubmit={::this.handleSubmit}>
<div className="field">
<input ref="email" id="user_email" type="email" placeholder="Email"  />
</div>
<div className="field">
<input ref="password" id="user_password" type="new-password" placeholder="Password"  />
</div>
<button type="submit">Sign up</button>
</form>
</main>
</div>
)
}


}
你应该注意到this取决于函数是如何被调用的 即:当一个函数作为一个对象的方法被调用时,它的this被设置为该方法被调用的对象

this可以作为你的组件对象在JSX上下文中访问,所以你可以内联调用你想要的方法this方法。

如果你只是把引用传递给函数/方法,react似乎会把它作为独立的函数调用。

onClick={this.onToggleLoop} // Here you just passing reference, React will invoke it as independent function and this will be undefined


onClick={()=>this.onToggleLoop()} // Here you invoking your desired function as method of this, and this in that function will be set to object from that function is called ie: your component object

在我的情况下,这是解决方案= () =>}

methodName = (params) => {
//your code here with this.something
}

在我的例子中,对于一个无状态的组件,它接收了带有forwardRef的ref,我必须做这里所说的https://itnext.io/reusing-the-ref-from-forwardref-with-react-hooks-4ce9df693dd

从这个(onClick没有访问'this'的等价物)

const Com = forwardRef((props, ref) => {
return <input ref={ref} onClick={() => {console.log(ref.current} } />
})

这(它工作)

const useCombinedRefs = (...refs) => {
const targetRef = React.useRef()


useEffect(() => {
refs.forEach(ref => {
if (!ref) return


if (typeof ref === 'function') ref(targetRef.current)
else ref.current = targetRef.current
})
}, [refs])


return targetRef
}


const Com = forwardRef((props, ref) => {
const innerRef = useRef()
const combinedRef = useCombinedRefs(ref, innerRef)


return <input ref={combinedRef } onClick={() => {console.log(combinedRef .current} } />
})

你可以重写如何从render()方法调用ontogglloop方法。

render() {
var shuffleClassName = this.state.toggleActive ? "player-control-icon active" : "player-control-icon"


return (
<div className="player-controls">
<FontAwesome
className="player-control-icon"
name='refresh'
onClick={(event) => this.onToggleLoop(event)}
spin={this.state.loopActive}
/>
</div>
);
}

反应的文档在从属性中的表达式调用函数时显示了这种模式。

我想解释为什么this是未定义的 如果在非箭头函数中使用this,则在非严格模式下,this将绑定到全局对象。但是在严格模式下,this将是undefined (https://www.w3schools.com/js/js_this.asp)

ES6模块总是处于严格模式(Javascript:在模块内部使用strict是不必要的)。

你可以在构造函数中使用bind方法将onToggleLoop函数中的thisPlayerControls组件的实例绑定:

constructor(props) {
super(props)


this.state = {
loopActive: false,
shuffleActive: false,
}


this.onToggleLoop = this.onToggleLoop.bind(this)
}

或者使用箭头函数:

onToggleLoop = (event) => {
this.setState({loopActive: !this.state.loopActive})
this.props.onToggleLoop()
}

箭头函数没有上下文,因此箭头函数中的this将表示定义箭头函数的对象。