Am scris-o simplă componentă în ES6 (cu BabelJS), și funcțiile de asta.setState` nu este de lucru.
Erori tipice includ ceva de genul
nu Poate citi de proprietate 'setState' de nedefinit
sau
acest lucru.setState nu este o funcție
Stii de ce? Aici este codul:
import React from 'react'
class SomeClass extends React.Component {
constructor(props) {
super(props)
this.state = {inputContent: 'startValue'}
}
sendContent(e) {
console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
}
changeContent(e) {
this.setState({inputContent: e.target.value})
}
render() {
return (
<div>
<h4>The input form is here:</h4>
Title:
<input type="text" ref="someref" value={this.inputContent}
onChange={this.changeContent} />
<button onClick={this.sendContent}>Submit</button>
</div>
)
}
}
export default SomeClass
acest lucru.changeContent are nevoie să fie legat la componenta exemplu prin asta.changeContent.bind(acest lucru) înainte de a fi trecut ca
onChange` cardanic, în caz contrar "asta" variabilă în corpul funcției, nu se va referi la componenta exemplu, dar la "fereastra". Vezi Function::bind.
Atunci când se utilizează a Reacționa.createClass
în loc de ES6 clase, fiecare non-ciclul de viață al metodei definite pe o componentă este automat legat de componenta exemplu. Vezi Autobinding.
Fi conștienți de faptul că obligatoriu o funcție creează o nouă funcție. Puteți fie să-l lega direct în render, ceea ce înseamnă o nouă funcție va fi creat de fiecare dată când componenta face, sau se leagă în constructor, care va trage doar o singură dată.
constructor() {
this.changeContent = this.changeContent.bind(this);
}
vs
render() {
return <input onChange={this.changeContent.bind(this)} />;
}
Arbitrii sunt stabilite pe componenta de instanță și nu pe Reacționa.refs: ai nevoie pentru a schimba pentru a Reacționa.ref.someref " la " asta.ref.someref
. Te'll, de asemenea, nevoie pentru a lega sendContent
metoda la componenta exemplu, astfel încât "asta" se referă la ea.
Morhaus este corectă, dar acest lucru poate fi rezolvată fără a lega
.
Puteți utiliza o săgeată funcția împreună cu proprietăți de clasă propunere:
class SomeClass extends React.Component {
changeContent = (e) => {
this.setState({inputContent: e.target.value})
}
render() {
return <input type="text" onChange={this.changeContent} />;
}
}
Deoarece săgeata funcție este declarată în aplicare de constructor, și pentru că săgeata funcții menține "asta" de la declararea lor de aplicare, totul funcționează. Dezavantajul aici este că aceste wont a fi funcțiile pe prototip, toate acestea vor fi recreat cu fiecare componentă. Cu toate acestea, acest lucru nu e't de mult de un dezavantaj, deoarece lega
rezultate la același lucru.
a Reacționa.createClass()
definirea componentelor de sintaxă la ES6 clasa a-și extinde a Reacționa.Componenta
.
Aceasta este cauzată de "acest" context diferențe în Reacționa.createClass()vs
se extinde Reacționa.Component`.
Folosind A Reacționa.createClass()
va lega în mod automat "acest" context (valori) corect, dar că nu este cazul atunci când se utilizează ES6 clase. Atunci când o faci ES6 mod (prin extinderea a Reacționa.Componentă
) de asta
context null
în mod implicit. Proprietățile de clasă nu se lega în mod automat pentru a Reacționa clasa (componentă) exemplu. Știu un total de 4 abordări generale.
Deși răspunsurile anterioare au furnizat prezentare generală de bază de soluții (de exemplu, legarea, săgeată funcții, decoratori care fac asta pentru tine), am'am încă să vină peste un răspuns care explică de fapt ce acest lucru este necesar—care în opinia mea este rădăcina de confuzie și duce la etape inutile, cum ar fi inutil re-legare și de a urma orbește ceea ce fac alții.
Pentru a înțelege această situație specifică, o scurtă introducere la modul în care aceasta funcționează. Cel mai important lucru aici este că "asta" este o execuție obligatorii și depinde de actualul context de executie. Prin urmare, de ce-l's de obicei menționată ca "context"—oferirea de informații în actualul context de execuție, și de ce aveți nevoie pentru a lega este pentru că ai pierdut "context". Dar lăsați-mă să ilustrez problema cu un fragment:
const foobar = {
bar: function () {
return this.foo;
},
foo: 3,
};
console.log(foobar.bar()); // 3, all is good!
În acest exemplu, vom obține 3
, cum era de așteptat. Dar să luăm acest exemplu:
const barFunc = foobar.bar;
console.log(barFunc()); // Uh oh, undefined!
Acesta poate fi neașteptată pentru a găsi că jurnalele nedefinit—unde s-a 3
te duci? Răspunsul se află în "context", sau cum ai execut o funcție. Compara cum numim noi funcții:
// Example 1
foobar.bar();
// Example 2
const barFunc = foobar.bar;
barFunc();
Observați diferența. În primul exemplu, avem de a specifica exact unde " bar " metoda1 este situat—pe foobar` obiect:
foobar.bar();
^^^^^^
Dar, în al doilea rând, ne-am stoca metoda într-o nouă variabilă, și de a folosi aceasta variabila pentru a apela metoda, fără să specifice explicit în cazul în care metoda de fapt există, pierzând astfel de context:
barFunc(); // Which object is this function coming from?
Și aici este o problemă, atunci când stocați o metodă într-o variabilă, informațiile originale despre cazul în care această metodă este situat (contextul în care metoda este de a fi executat), este pierdut. Fără aceste informații, la runtime, nu există nici o modalitate pentru JavaScript interpret pentru a lega corect "asta" —fără context specific, "asta" nu funcționează cum era de așteptat2.
Aici's un exemplu de reacție de componentă (scurtat pentru concizie) care suferă de această problemă:
handleClick() {
this.setState(({ clicks }) => ({ // setState is async, use callback to access previous state
clicks: clicks + 1, // increase by 1
}));
}
render() {
return (
<button onClick={this.handleClick}>{this.state.clicks}</button>
);
}
Dar de ce, și cum nu-secțiunea precedentă se referă la acest lucru? Acest lucru este pentru că ei suferă de o abstracție de aceeași problemă. Dacă aruncăm o privire la modul de a Reacționa se ocupă de eveniment handlers](https://github.com/facebook/react/blob/64e1921aab4f7ad7e2f345f392033ffe724e52e9/packages/events/EventPluginHub.js#L148):
// Edited to fit answer, React performs other checks internally
// props is the current React component's props, registrationName is the name of the event handle prop, i.e "onClick"
let listener = props[registrationName];
// Later, listener is called
Deci, atunci când faci onClick={acest.handleClick}
, metoda asta.handleClickeste în cele din urmă atribuit variabilei
ascultator<sup>3</sup>. Dar acum vezi tu problema, apar—când ne-am'am atribuit
asta.handleClick " la " ascultătorului, nu mai specifica exact unde handleClickvine de la! De a Reacționa's punct de vedere,
ascultatoreste doar o funcție, nu atașat la orice obiect (sau, în acest caz, Reacționează componentă de exemplu). Ne-am pierdut context și, astfel, interpretul nu poate deduce o
această valoare pentru a utiliza interior handleClick
.
Ați putea fi întrebam, dacă interpretul decide "această" valoare la runtime, ce pot lega handler, astfel încât acesta funcționează? Acest lucru este pentru că puteți utiliza Funcția#bind` a garanție la "această" valoare la runtime. Acest lucru se face prin stabilirea unui interne "asta" legare de proprietate pe o funcție, permițându-i să nu se deducă "asta":
this.handleClick = this.handleClick.bind(this);
Când această linie este executat, probabil în constructor, actual "asta" este capturat (React componentă de exemplu) și a stabilit ca un intern "asta" legarea de o cu totul nouă funcție, a revenit la Funcția de#lega`. Acest lucru face sigur că atunci când "asta" se calculează la runtime, interpretul nu va încerca să deducă nimic, dar utilizați furnizate "această" valoare ai dat-o.
Săgeata în funcție de clasa de proprietăți de lucru în prezent, prin Babel bazează pe transpilation:
handleClick = () => { /* Can use this just fine here */ }
Devine:
constructor() {
super();
this.handleClick = () => {}
}
acest
a lor anexând domeniul de aplicare. În acest caz, constructorul
's "această", care subliniază Reacționa componentă exemplu—astfel oferindu-vă corect "acesta".4 1 nu utiliza "metoda" pentru a se referi la o funcție care ar trebui să fie legat de un obiect, și "funcția" pentru cei care nu sunt.
2 În cel de-al doilea fragment, nedefinit este conectat în loc de 3, pentru că "asta" implicite la nivel global context de executie ("fereastra" atunci când nu este în mod strict, sau altceva "nedefinit") atunci când nu poate fi determinată prin context specific. Și în exemplul de fereastră.foonu exista astfel obținându nedefinit. <sup>3</sup> Dacă te duci în jos gaura de iepure de cum evenimentelor din coada de evenimente sunt executate, [
invokeGuardedCallback`](https://github.com/facebook/react/blob/64e1921aab4f7ad7e2f345f392033ffe724e52e9/packages/shared/invokeGuardedCallback.js#L27) este numit pe ascultător.
4 It's de fapt o mult mai complicat. Reacționează intern încearcă să utilizeze Funcția#se aplică pe ascultători pentru uz propriu, dar acest lucru nu funcționează săgeată funcții ca ei pur și simplu nu se leagă "asta". Asta înseamnă că, atunci când "asta" în interiorul săgeată funcție este, de fapt evaluate, "asta" este rezolvată de fiecare lexicale mediu din fiecare context de executie din actualul cod de module. Contextul de executie care în cele din urmă decide să aibă un "asta" obligatoriu este constructorul, care are un "asta" arătând spre actual de a Reacționa componentă de exemplu, permițându-i să lucreze.
Recomandarea mea este să utilizați săgeată funcționează ca un proprietăți
class SomeClass extends React.Component {
handleClick = () => {
console.log(this); // the React Component instance
}
render() {
return (
<button onClick={this.handleClick}></button>
);
}
}
și nu utilizați săgeată funcții ca
class SomeClass extends React.Component {
handleClick(){
console.log(this); // the React Component instance
}
render() {
return (
<button onClick={()=>{this.handleClick}}></button>
);
}
}
pentru că a doua abordare va genera noi funcția fiecare face apel, în fapt, aceasta înseamnă noi pointer nouă versiune de recuzită, decât dacă mai târziu va pasa de performanță vă sunt capabili de a utiliza Reacționa.PureComponent sau Reacționa.Componenta puteți suprascrie shouldComponentUpdate(nextProps, nextState) și superficială a verifica atunci când recuzita ajuns
Avem nevoie pentru a lega funcția de eveniment cu componentă în constructor, după cum urmează,
import React from 'react'
class SomeClass extends React.Component {
constructor(props) {
super(props)
this.state = {inputContent: 'startValue'}
this.changeContent = this.changeContent.bind(this);
}
sendContent(e) {
console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
}
changeContent(e) {
this.setState({inputContent: e.target.value})
}
render() {
return (
<div>
<h4>The input form is here:</h4>
Title:
<input type="text" ref="someref" value={this.inputContent}
onChange={this.changeContent} />
<button onClick={this.sendContent}>Submit</button>
</div>
)
}
}
export default SomeClass
Multumesc
Trebuie să lega
funcția noastră cu "asta" să ia exemplu de funcție în clasă. Așa de exemplu
<button onClick={this.sendContent.bind(this)}>Submit</button>
În acest fel asta.stat
va fi valabil obiect.
Puteți rezolva acest lucru, urmând acești pași
Schimba sendContent funcția cu
sendContent(e) {
console.log('sending input content '+this.refs.someref.value)
}
Schimbarea face cu funcția
<input type="text" ref="someref" value={this.state.inputContent}
onChange={(event)=>this.changeContent(event)} />
<button onClick={(event)=>this.sendContent(event)}>Submit</button>
Puteți aborda acest lucru prin trei moduri
1.Lega funcția de eveniment în constructor în sine, după cum urmează
import React from 'react'
class SomeClass extends React.Component {
constructor(props) {
super(props)
this.state = {inputContent: 'startValue'}
this.changeContent = this.changeContent.bind(this);
}
sendContent(e) {
console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
}
changeContent(e) {
this.setState({inputContent: e.target.value})
}
render() {
return (
<div>
<h4>The input form is here:</h4>
Title:
<input type="text" ref="someref" value={this.inputContent}
onChange={this.changeContent} />
<button onClick={this.sendContent}>Submit</button>
</div>
)
}
}
export default SomeClass
2.Se leagă atunci când este chemat
import React from 'react'
class SomeClass extends React.Component {
constructor(props) {
super(props)
this.state = {inputContent: 'startValue'}
}
sendContent(e) {
console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
}
changeContent(e) {
this.setState({inputContent: e.target.value})
}
render() {
return (
<div>
<h4>The input form is here:</h4>
Title:
<input type="text" ref="someref" value={this.inputContent}
onChange={this.changeContent} />
<button onClick={this.sendContent.bind(this)}>Submit</button>
</div>
)
}
}
export default SomeClass
3.By folosind Săgeata funcții
import React from 'react'
class SomeClass extends React.Component {
constructor(props) {
super(props)
this.state = {inputContent: 'startValue'}
}
sendContent(e) {
console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
}
changeContent(e) {
this.setState({inputContent: e.target.value})
}
render() {
return (
<div>
<h4>The input form is here:</h4>
Title:
<input type="text" ref="someref" value={this.inputContent}
onChange={this.changeContent} />
<button onClick={()=>this.sendContent()}>Submit</button>
</div>
)
}
}
export default SomeClass
bind(acest lucru)
se poate repara această problemă, și în zilele noastre putem folosi inca 2 moduri de a realiza acest lucru, dacă nu't ca folosind lega
.
bind(acest lucru)
în constructor, astfel încât, atunci când am folosit funcția ca JSX apel invers, în contextul "asta" este clasa în sine.`` clasa App1 se extinde Reacționa.Componenta { constructor(popi) { super(popi); // Daca am comentați următoarea linie, // vom obtine eroare de timp a alerga, a spus "asta" este nedefinit. acest lucru.changeColor = acest lucru.changeColor.bind(acest lucru); }
changeColor(e) { e.currentTarget.stil.backgroundColor = "#00FF00"; console.log(acest lucru.elemente de recuzită); }
render() { retur (
Dacă definim funcția ca un atribut/domeniul de clasa cu săgeata în funcție, nu ne't nevoie pentru a folosi bind(acest lucru)` orice mai mult. `` clasa App2 se extinde Reacționa.Componenta { changeColor = e => { e.currentTarget.stil.backgroundColor = "#00FF00"; console.log(acest lucru.elemente de recuzită); }; render() { retur (
Dacă vom folosi săgeată funcționa ca JSX de apel invers, nu ne't nevoie pentru a folosi bind(acest lucru)` fie. Și mai mult, putem trece în parametri. Arata bine, e't-l? dar dezavantaj este interes de performanță, pentru detalii vă rugăm să consultați ReactJS doco. `` clasa App3 se extinde Reacționa.Componenta { changeColor(e, colorHex) { e.currentTarget.stil.backgroundColor = colorHex; console.log(acest lucru.elemente de recuzită); } render() { retur (
Și am creat un Codepen pentru a demo de aceste fragmente de cod, sper că vă ajută.
dacă cineva se va ajunge vreodata la acest răspuns, aici este o modalitate de a lega toate funcțiile fără a fi nevoie de a le lega manual
în constructor():
for (let member of Object.getOwnPropertyNames(Object.getPrototypeOf(this))) {
this[member] = this[member].bind(this)
}
sau pentru a crea această funcție într-un sistem global.jsx
export function bindAllFunctions({ bindTo: dis }) {
for (let member of Object.getOwnPropertyNames(Object.getPrototypeOf(dis))) {
dis[member] = dis[member].bind(dis)
}
}
și în constructor() spune ca:
bindAllFunctions({ bindTo: this })
Această problemă se întâmplă din cauza asta.changeContent " și " onClick={acest.sendContent}` nu sunt obligat să - acest de exemplu de componenta .
Nu există o altă soluție (În plus față de utilizarea bind() în constructorul() ) pentru a utiliza săgeata funcții de ES6 care împărtășesc aceleași sfera lexicală din jur cod și menține acest , astfel încât să puteți schimba codul în render() să fie :
render() {
return (
<input type="text"
onChange={ () => this.changeContent() } />
<button onClick={ () => this.sendContent() }>Submit</button>
)
}
Salut, dacă vrei să nu-mi pasa de legare singur apel de funcție. Puteți folosi 'clasa autobind' și de import-l asa
import autobind from 'class-autobind';
class test extends Component {
constructor(props){
super(props);
autobind(this);
}
Nu scrie autobind înainte de super apel, deoarece acesta nu va funcționa
În cazul în care doriți să păstrați lega în constructor sintaxa, puteți utiliza propunere-bind-operator și transforma codul cum urmează :
constructor() {
this.changeContent = ::this.changeContent;
}
În loc de :
constructor() {
this.changeContent = this.changeContent.bind(this);
}
mult mai simplă, nu este nevoie de lega(aceasta) " sau " fatArrow
.
această problemă se întâmplă după react15.0 ,care tratare a evenimentului nu't auto se leagă de componenta. așa că trebuie să o lege pe această componentă a manual ori de câte ori tratare a evenimentului va fi numit.
există mai multe metode pentru a rezolva problema. dar trebuie să știi care este cea mai bună metodă și de ce? În general, vă recomandăm obligatoriu funcțiile în constructorul clasei sau de a folosi o săgeată funcție.
// method 1: use a arrow function
class ComponentA extends React.Component {
eventHandler = () => {
console.log(this)
}
render() {
return (
<ChildComponent onClick={this.eventHandler} />
);
}
// method 2: Bind your functions in the class constructor.
class ComponentA extends React.Component {
constructor(props) {
super(props);
this.eventHandler = this.eventHandler.bind(this);
}
render() {
return (
<ChildComponent onClick={this.eventHandler} />
);
}
aceste două metode nu va creează o nouă funcție, atunci când componenta face de fiecare dată. deci ChildComponent nu va reRender becaue din nou funcția de recuzită schimba, sau poate produce problemă de performanță.
Funcțiile trebuie obligatoriu în scopul de a juca cu stat sau de elemente de recuzită în stivuitoare eveniment
În ES5, se leaga de tratare a evenimentului funcții numai în constructor, dar don't se leaga direct la render. Dacă veți face obligatoriu direct în render atunci se creează o nouă funcție, de fiecare dată când componentă face și re-face. Deci, ar trebui să întotdeauna se leagă în constructor
this.sendContent = this.sendContent.bind(this)
În ES6, utilizați săgeata de funcții
Atunci când utilizați săgeată funcții apoi, aveți nevoie pentru a face obligatoriu și puteți, de asemenea, stai departe de probleme legate de domeniul de aplicare
sendContent = (event) => {
}
Alexandre Kirszenberg este corect, Dar un alt lucru important să se acorde atenție , este în cazul în care ți-ai pus obligatorii. Am fost blocat cu o situație de zile(probabil pentru că am'm un incepator), dar spre deosebire de alții, am știut despre bind(pe Care am aplicat-o deja), așa că am putea't obține capul meu în jurul valorii de ce am mai avea aceste erori. Se pare că am avut bind în ordine greșită.
Alta este, de asemenea, poate faptul că am fost sunat funcția în cadrul "acest lucru.de stat", care nu a fost conștient de a lega pentru că s-a întâmplat să fie deasupra lega de linie,
Mai jos este ceea ce am avut(apropo, aceasta este prima mea postare, Dar am crezut că a fost foarte important, cum am putea't găsi o soluție în cazul în care orice altceva):
constructor(props){
super(props);
productArray=//some array
this.state={
// Create an Array which will hold components to be displayed
proListing:productArray.map(product=>{return(<ProRow dele={this.this.popRow()} prodName={product.name} prodPrice={product.price}/>)})
}
this.popRow=this.popRow.bind(this);//This was the Issue, This line //should be kept above "this.state"
Soluție:
bind
cu nume de metodă puteți folosi grăsime săgeată funcții sintaxa ()=>{} care menține contextul de "asta".`` import Reacționa la 'de a reacționa'
class SomeClass se extinde Reacționa.Componenta { constructor(popi) { super(popi) acest lucru.de stat = { inputContent: 'startValue' } }
sendContent = (e) => { console.log('trimiterea de conținut de intrare ',acest lucru.de stat.inputContent); }
changeContent = (e) => { acest lucru.setState({inputContent: e.țintă.valoarea},()=>{ console.log('STARE:',acest lucru.de stat); }) }
render() { retur (
export default SomeClass
``
Alte Soluții:
Leagă-ți funcții în constructorul clasei.
Leagă-ți funcții în JSX Șablon evadarea bretele {} {acest.code.bind(acest)}