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

React: "this" is undefined inside a component function

提问人:Maximus S 提问时间:11/29/2015 最后编辑:Emile BergeronMaximus S 更新时间:4/12/2023 访问量:172073

问:

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

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

javascript reactjs 这个

评论


答:

109赞 J. Mark Stevens 11/29/2015 #1

有几种方法。

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

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

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

评论

4赞 Guchelkaben 9/15/2017
为什么 onToogleLoop = () => {} 有效?我遇到了同样的问题,我把它装订在我的构造函数中,但它不起作用......现在我已经看到了你的帖子,并用箭头函数语法替换了我的方法,它有效。你能给我解释一下吗?
8赞 J. Mark Stevens 9/16/2017
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...;箭头函数不会创建自己的 this,而是使用封闭执行上下文的 this 值。
3赞 Ninjakannon 5/25/2018
请注意,在 中内联绑定将在每次渲染时返回一个新函数,因此看起来已经为道具传递了一个新值,在 s 中搞砸了。onClickshouldComponentUpdatePureComponent
281赞 Ivan 11/29/2015 #2

ES6 不会自动将方法绑定到自身。您需要自己将它们绑定在 .喜欢这个:React.Componentconstructor

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

}

评论

38赞 Sam 8/27/2016
如果你将 onClick 属性更改为将 onToggleLoop 函数移动到 react 类中后,它也会起作用。() => this.onToggleLoop
91赞 Alex L 10/6/2016
你真的必须绑定每个 react 类的每个方法吗?是不是有点疯狂?
7赞 Ivan 10/7/2016
@AlexL 有一些方法可以在不显式绑定方法的情况下做到这一点。如果你使用 Babel,则可以将 React 组件上的每个方法声明为箭头函数。这里有一些例子:babeljs.io/blog/2015/06/07/react-on-es6-plus
12赞 darKnight 1/4/2018
但是,为什么一开始就没有定义呢?我知道 Javascript 取决于函数的调用方式,但这里发生了什么?thisthis
4赞 OscarRyz 6/11/2019
文章的TLDR:改用箭头函数。
12赞 duhaime 6/24/2016 #3

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

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

我还使用过:

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

评论

1赞 T.J. Crowder 2/9/2018
每次渲染列表时,您都会在那里创建许多不必要的函数......
0赞 duhaime 2/9/2018
@T.J.Crowder:是的,确实,每次调用渲染时都会重新创建这些函数。最好将函数创建为类方法并将它们绑定一次到类中,但对于初学者来说,手动上下文绑定可能会有所帮助
0赞 Guchelkaben 9/15/2017 #4

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

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

37赞 ShaTin 12/4/2017 #5

这样编写函数:

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

胖箭头函数

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

评论

0赞 Pavel Komarov 6/26/2019
如果我这样做,我会得到.ReferenceError: fields are not currently supported
1赞 Pavel Komarov 6/26/2019
如果在构造函数中我说 this.func = () => { ... },它就会起作用,但我认为这有点愚蠢,并希望尽可能避免它。
2赞 Kokodoko 7/11/2019
太可怕了,你不能在 React 中使用普通的类语法!
1赞 Henry Jacob 3/14/2019 #6

如果你使用的是 babel,则使用 ES7 绑定运算符绑定 '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>
    )
  }

}
3赞 Jakub Kutrzeba 9/6/2019 #7

您应该注意到,这取决于函数的调用方式 即:当函数作为对象的方法调用时,它被设置为调用该方法的对象。thisthis

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

评论

1赞 gvlax 9/12/2019
是的,您甚至可以使用第一行,即 前提是在组件类中定义了一个字段(属性)onClick={this.onToggleLoop}onToggleLoop = () => /*body using 'this'*/
4赞 Alex 12/19/2019 #8

就我而言,这就是解决方案= () => {}

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

评论

0赞 Nathan Gouy 7/2/2021
这才是真正的解决方案。忘了把它放在一个让我失望的功能上,谢谢
0赞 GWorking 1/15/2020 #9

就我而言,对于使用 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} } />
})
0赞 T. Webster 10/16/2020 #10

您可以从 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 文档在从属性中的表达式调用函数时展示了这种模式。

1赞 Quan Le Minh 7/23/2022 #11

我想解释一下为什么是未定义的:
如果我们在一个不是箭头函数的函数中使用,那么在不处于严格模式时会绑定到一个全局对象。但是使用严格模式,将是未定义的(https://www.w3schools.com/js/js_this.asp)。
thisthisthisthis

并且 ES6 模块始终处于严格模式(javascript:在模块内部不需要使用严格)。

您可以在函数中使用构造函数中的方法与组件的实例绑定:thisonToggleLoopPlayerControlsbind

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

评论

1赞 Lee 7/25/2022
添加一些关于能够绑定它以提供上下文的内容。JS 中的概念可能非常令人困惑,通常需要更多的解释。
-1赞 DariusG 4/5/2023 #12

我最近遇到了“这是未定义的”错误,以下方法对我有用。我将状态传递给我的类构造函数,并且只需将用作箭头函数的函数传递给我的侦听器。

const cartUtils: CartUtils = new CartUtils(cartItems, setCartItems);

onClick={(evt) => cartUtils.getProductInfo(evt)}