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

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

有几种方法。

一个是添加 this.onToggleLoop = this.onToggleLoop.bind(this); 在构造函数中。

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

然后是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

the binding for the keyword this is the same outside and inside the fat arrow function. This is different than functions declared with function, which can bind this to another object upon invocation. Maintaining the this binding is very convenient for operations like mapping: this.items.map(x => this.doSomethingWith(x)).

如果您使用的是 babel,则使用 E​​S7 绑定运算符绑定 'this' https://babeljs.io/docs/en/babel-plugin-transform-function-bind#auto-self-binding

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 方法。

如果你只是传递对function/method的引用,似乎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() 方法调用 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>
    );
  }

React documentation 显示了从属性中的表达式调用函数的这种模式。