简体   繁体   English

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

[英]React: "this" is undefined inside a component function

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()
  }

I want to update loopActive state on toggle, but this object is undefined in the handler.我想在切换时更新loopActive状态,但this对象在处理程序中未定义。 According to the tutorial doc, I this should refer to the component.根据教程文档,我this应该是指组件。 Am I missing something?我错过了什么吗?

ES6 React.Component doesn't auto bind methods to itself. ES6 React.Component不会自动将方法绑定到自身。 You need to bind them yourself in constructor .您需要自己在constructor绑定它们。 Like this:像这样:

constructor (props){
  super(props);
  
  this.state = {
      loopActive: false,
      shuffleActive: false,
    };
  
  this.onToggleLoop = this.onToggleLoop.bind(this);

}

There are a couple of ways.有几种方法。

One is to add this.onToggleLoop = this.onToggleLoop.bind(this);一种是添加this.onToggleLoop = this.onToggleLoop.bind(this); in the constructor.在构造函数中。

Another is arrow functions onToggleLoop = (event) => {...} .另一个是箭头函数onToggleLoop = (event) => {...}

And then there is onClick={this.onToggleLoop.bind(this)} .然后是onClick={this.onToggleLoop.bind(this)}

Write your function this way:这样写你的函数:

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

Fat Arrow Functions粗箭头函数

the binding for the keyword this is the same outside and inside the fat arrow function.关键字 this 的绑定在胖箭头函数的外部和内部是相同的。 This is different than functions declared with function, which can bind this to another object upon invocation.这与使用 function 声明的函数不同,后者可以在调用时将 this 绑定到另一个对象。 Maintaining the this binding is very convenient for operations like mapping: this.items.map(x => this.doSomethingWith(x)).维护 this 绑定对于映射之类的操作非常方便:this.items.map(x => this.doSomethingWith(x))。

I ran into a similar bind in a render function and ended up passing the context of this in the following way:我在渲染函数中遇到了类似的绑定,最终以下列方式传递了this的上下文:

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

I've also used:我也用过:

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

You should notice that this depends on how function is invoked ie: when a function is called as a method of an object, its this is set to the object the method is called on.您应该注意到this取决于函数的调用方式,即:当一个函数作为对象的方法被调用时,它的this被设置为调用该方法的对象。

this is accessible in JSX context as your component object, so you can call your desired method inline as this method. this可以作为组件对象在 JSX 上下文中访问,因此您可以将所需的方法内联调用this方法。

If you just pass reference to function/method, it seems that react will invoke it as independent function.如果您只是传递对函数/方法的引用,则 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

If you are using babel, you bind 'this' using ES7 bind operator https://babeljs.io/docs/en/babel-plugin-transform-function-bind#auto-self-binding如果您使用 babel,则使用 E​​S7 绑定运算符https://babeljs.io/docs/en/babel-plugin-transform-function-bind#auto-self-binding绑定“this”

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>
    )
  }

}

in my case this was the solution = () => {}就我而言,这是解决方案= () => {}

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

If you call your created method in the lifecycle methods like componentDidMount... then you can only use the this.onToggleLoop = this.onToogleLoop.bind(this) and the fat arrow function onToggleLoop = (event) => {...} .如果你在生命周期方法中调用你创建的方法,比如 componentDidMount... 那么你只能使用this.onToggleLoop = this.onToogleLoop.bind(this)this.onToggleLoop = this.onToogleLoop.bind(this)箭头函数onToggleLoop = (event) => {...} .

The normal approach of the declaration of a function in the constructor wont work because the lifecycle methods are called earlier.在构造函数中声明函数的正常方法将不起作用,因为生命周期方法被调用得更早。

In my case, for a stateless component that received the ref with forwardRef, I had to do what it is said here https://itnext.io/reusing-the-ref-from-forwardref-with-react-hooks-4ce9df693dd就我而言,对于接收带有 forwardRef 的 ref 的无状态组件,我必须按照此处所说的进行操作https://itnext.io/reusing-the-ref-from-forwardref-with-react-hooks-4ce9df693dd

From this (onClick doesn't have access to the equivalent of 'this')从此(onClick 无法访问等效于“this”的内容)

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

To this (it works)对此(它有效)

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} } />
})

You can rewrite how your onToggleLoop method is called from your render() method.您可以重写如何从 render() 方法调用 onToggleLoop 方法。

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>
    );
  }

The React documentation shows this pattern in making calls to functions from expressions in attributes. React 文档显示了从属性中的表达式调用函数的这种模式。

I want to give an explanation why this is undefined:我想解释一下为什么this是未定义的:
If we use this in a function that is not an arrow function, this is bound to a global object when not in strict mode.如果我们在非箭头函数的函数中使用this ,则this在非严格模式下绑定到全局对象。 But with strict mode, this will be undefined ( https://www.w3schools.com/js/js_this.asp ).但是在严格模式下, this将是未定义的( https://www.w3schools.com/js/js_this.asp )。

And ES6 modules are always in strict mode ( javascript: use strict is unnecessary inside of modules ).并且 ES6 模块始终处于严格模式( javascript: use strict 在模块内部是不必要的)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM