Tepki: “this” bir bileşen işlevi içinde tanımlanmamış


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

loopActiveGeçiş durumundaki durumu güncellemek istiyorum , ancak thisnesne işleyicide tanımsız. Öğretici dokümana göre this, bileşene başvurmalıyım. Bir şey mi kaçırıyorum?

Yanıtlar:


211

ES6 React.Component yöntemleri otomatik olarak kendisine bağlamaz. Onları yapıcıda kendiniz bağlamanız gerekir. Bunun gibi:

constructor (props){
  super(props);

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

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

}

23
() => this.onToggleLooponToggleLoop işlevini tepki sınıfınıza taşıdıktan sonra onClick özelliğini değiştirirseniz, bu özellik de çalışır.
Sam

71
Gerçekten her tepki sınıfının her yöntemini bağlamak zorunda mısınız? Bu biraz çılgınca değil mi?
Alex L

6
@AlexL Yöntemleri açıkça bağlamadan bunu yapmanın yolları vardır. babel kullanıyorsanız, React bileşenindeki her yöntemi ok işlevleri olarak bildirmek mümkündür. Burada örnekler var: babeljs.io/blog/2015/06/07/react-on-es6-plus
Ivan

7
Ama neden thisilk başta tanımsız? thisJavascript'te işlevin nasıl çağrıldığına bağlı olduğunu biliyorum , ama burada neler oluyor?
maverick

1
ama bu yapıcı sonra kadar fonksiyon tanımlanmamış olduğunu nasıl yapabilirim? Eğer
rex

87

Birkaç yol var.

Birincisi yapıcıya eklemektir this.onToggleLoop = this.onToggleLoop.bind(this);.

Diğeri ok fonksiyonlarıdır onToggleLoop = (event) => {...}.

Ve sonra var onClick={this.onToggleLoop.bind(this)}.


1
OnToogleLoop = () => {} neden çalışıyor? Ben aynı sorunu var ve ben benim yapıcı bindet ama işe yaramadı ... ve şimdi ben senin yazı gördüm ve bir ok işlevi sözdizimi ile yöntemimi değiştirin ve işe yarıyor. Bunu bana açıklayabilir misin ?
Guchelkaben

5
adlı developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... ; Bir ok işlevi bunu oluşturmaz, ekteki yürütme bağlamının bu değeri kullanılır.
J. Mark Stevens

1
Satır içinde bağlayıcı olduğunu Not onClickyeni fonksiyon her işlemek ve yeni bir değer karıştırmasını, pervane geçti gibi böylece görünüyor dönecektir shouldComponentUpdateiçinde PureComponents.
Ninjakannon

25

İşlevinizi şu şekilde yazın:

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

Yağ Ok Fonksiyonları

anahtar kelime için bağlanma, bu yağ ok işlevinin içinde ve dışında aynıdır. Bu işlev çağrıldığında başka bir nesneye bağlayabilen işlevle bildirilen işlevlerden farklıdır. Bu bağlamanın korunması, eşleme gibi işlemler için çok uygundur: this.items.map (x => this.doSomethingWith (x)).


Bunu yaparsam anlarım ReferenceError: fields are not currently supported.
Pavel Komarov

Eğer yapıcı içinde bunu söylersem çalışır.
Pavel Komarov

Öylesine korkunç ki React'ta normal sınıf sözdizimini kullanamazsınız!
Kokodoko

11

Bir render fonksiyonunda benzer bir bağla karşılaştım ve bağlamını thisaşağıdaki şekilde geçtim :

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

Ayrıca kullandım:

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

Bu, listeyi her oluşturduğunuzda, orada oluşturduğunuz birçok gereksiz işlev var ...
TJ Crowder

@TJCrowder Evet, bu işlevler oluşturma işlemi her çağrıldığında yeniden oluşturulur. İşlevleri sınıf yöntemleri olarak oluşturmak ve bunları bir kez sınıfa bağlamak daha iyidir, ancak yeni başlayanlar için manuel bağlam bağlama yardımcı olabilir
duhaime

2

thisİşlevin nasıl çağrıldığına bağlı olduğunu fark etmelisiniz , örneğin: bir işlev bir nesnenin thisyöntemi olarak çağrıldığında, yöntemin çağrıldığı nesneye ayarlanır.

thisbileşen nesneniz olarak JSX bağlamında erişilebilir, böylece istediğiniz yöntemi satır içi thisyöntem olarak çağırabilirsiniz .

Eğer sadece fonksiyona / yönteme referans iletirseniz, tepki o fonksiyonu bağımsız fonksiyon olarak çağırır.

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
Doğru, ilk satırı bile kullanabilirsiniz, yani onClick={this.onToggleLoop}bileşen sınıfınızda bir alan (özellik) onToggleLoop = () => /*body using 'this'*/
tanımlamanız koşuluyla

1

Babel kullanıyorsanız, ES7 bağlama operatörünü kullanarak 'this'i bağlarsınız 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>
    )
  }

}

0

Oluşturulan yönteminizi componentDidMount ... gibi yaşam döngüsü yöntemlerinde çağırırsanız , yalnızca this.onToggleLoop = this.onToogleLoop.bind(this)ve yağ ok işlevini kullanabilirsiniz onToggleLoop = (event) => {...}.

Yaşam döngüsü yöntemleri daha önce çağrıldığından, yapıcıdaki bir işlev bildiriminin normal yaklaşımı işe yaramaz.


0

benim durumumda bu çözüm = () => {}

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

0

Benim durumumda, iletiyi forwardRef ile alan vatansız bir bileşen için, burada söylediklerini yapmak zorunda kaldım https://itnext.io/reusing-the-ref-from-forwardref-with-react-hooks-4ce9df693dd

Bundan (onClick, 'this' eşdeğerine erişemez)

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

Buna (işe yarıyor)

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} } />
})
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.