Saya menulis sebuah komponen sederhana dalam ES6 (dengan BabelJS), dan fungsi ini.setState
tidak bekerja.
Kesalahan khas meliputi sesuatu seperti
Tidak bisa membaca properti 'setState' undefined
atau
ini.setState tidak fungsi
Apakah anda tahu mengapa? Berikut ini adalah kode:
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
ini.changeContent
kebutuhan untuk terikat dengan komponen misalnya melalui ini.changeContent.bind(this)
sebelum disahkan sebagai onChange
prop, jika ini
variabel dalam tubuh fungsi tidak akan mengacu pada komponen contoh tapi untuk jendela
. Lihat Function::bind.
Ketika menggunakan Bereaksi.createClass
bukan ES6 kelas, setiap non-siklus hidup metode yang didefinisikan pada sebuah komponen secara otomatis terikat pada komponen contoh. Lihat Autobinding.
Diketahui bahwa mengikat sebuah fungsi menciptakan fungsi baru. Anda dapat mengikat langsung di render, yang berarti fungsi baru akan dibuat setiap kali komponen membuat, atau mengikatnya dalam constructor, yang hanya akan api sekali.
constructor() {
this.changeContent = this.changeContent.bind(this);
}
vs
render() {
return <input onChange={this.changeContent.bind(this)} />;
}
Ref ditetapkan pada komponen contoh dan bukan pada Bereaksi.ref
: yang anda butuhkan untuk mengubah Bereaksi.ref.someref
untuk ini.ref.someref
. Anda'll juga perlu untuk mengikat sendContent
metode untuk komponen contoh sehingga ini
menunjuk pada hal itu.
Morhaus adalah benar, tetapi ini dapat diselesaikan tanpa mengikat
.
Anda dapat menggunakan panah fungsi bersama-sama dengan properti kelas proposal:
class SomeClass extends React.Component {
changeContent = (e) => {
this.setState({inputContent: e.target.value})
}
render() {
return <input type="text" onChange={this.changeContent} />;
}
}
Karena panah fungsi dinyatakan dalam lingkup konstruktor, dan karena panah fungsi mempertahankan ini
dari mereka menyatakan ruang lingkup, itu semua bekerja. Kelemahan di sini adalah bahwa ini tidak akan berfungsi pada prototipe, mereka semua akan diciptakan dengan masing-masing komponen. Namun, ini isn't banyak dari sisi negatifnya karena mengikat
hasil dalam hal yang sama.
Bereaksi.createClass()
komponen definisi sintaks untuk ES6 kelas cara memperpanjang Bereaksi.Komponen
.
Hal ini disebabkan oleh ini
konteks perbedaan Bereaksi.createClass()
vs meluas Bereaksi.Komponen
.
Menggunakan Bereaksi.createClass()
secara otomatis akan mengikat ini
konteks (nilai-nilai) dengan benar, tapi itu tidak terjadi ketika menggunakan ES6 kelas. Ketika melakukan itu ES6 cara (dengan memperpanjang Bereaksi.Komponen
) yang ini
konteks null
secara default. Sifat-sifat kelas tidak secara otomatis mengikat Bereaksi kelas (komponen) misalnya. Aku tahu total 4 pendekatan umum.
ini
nilai. Namun, panah fungsi tidak menciptakan sendiri ini
konteks, sehingga ini
memiliki makna asli dari Bereaksi komponen misalnya. Oleh karena itu, kita dapat:
kelas SomeClass meluas Bereaksi.Komponen {
handleClick() {
konsol.log(ini); // yang Bereaksi Komponen contoh
}
render() {
return (
<button onClick={ () => ini.handleClick() }>
);
}
}
atau
kelas SomeClass meluas Bereaksi.Komponen {
handleClick = () => {
konsol.log(ini); // yang Bereaksi Komponen contoh
}
render() {
return ( ini
, bahkan ketika metode yang terpisah. Paket menggunakan @autobind
sebelum metode untuk mengikat ini
untuk referensi yang benar komponen's konteks.
impor autobind dari 'autobind-dekorator';
kelas SomeClass meluas Bereaksi.Komponen {
@autobind
handleClick() {
konsol.log(ini); // yang Bereaksi Komponen contoh
}
render() {
return ( ini
.
impor autobind dari 'kelas-autobind';
kelas SomeClass meluas Bereaksi.Komponen {
konstruktor() {
autobind(ini);
// atau jika anda ingin mengikat hanya hanya memilih fungsi:
// autobind(ini, 'handleClick');
}
handleClick() {
konsol.log(ini); // yang Bereaksi Komponen contoh
}
render() {
return ( Meskipun jawaban sebelumnya telah memberikan gambaran dasar dari solusi (yaitu mengikat, panah fungsi, dekorator yang melakukan ini untuk anda), saya've belum menemukan jawaban yang benar-benar menjelaskan mengapa ini adalah diperlukan—yang menurut saya adalah akar dari kebingungan, dan mengarah ke langkah yang tidak perlu seperti tak rebinding dan membabi buta mengikuti apa yang orang lain lakukan.
ini
adalah dinamisUntuk mengerti ini situasi tertentu, pengenalan singkat bagaimana ini
bekerja. Kuncinya di sini adalah bahwa ini
adalah sebuah runtime yang mengikat dan tergantung pada saat eksekusi konteks. Maka mengapa itu's sering disebut sebagai "konteks"—memberikan informasi pada saat eksekusi konteks, dan mengapa anda perlu untuk mengikat adalah karena anda kehilangan "konteks". Tapi mari saya ilustrasikan masalah dengan cuplikan:
const foobar = {
bar: function () {
return this.foo;
},
foo: 3,
};
console.log(foobar.bar()); // 3, all is good!
Dalam contoh ini, kita mendapatkan 3
, seperti yang diharapkan. Tapi ambil contoh ini:
const barFunc = foobar.bar;
console.log(barFunc()); // Uh oh, undefined!
Mungkin tak terduga untuk menemukan bahwa itu log undefined—mana 3
pergi? Jawabannya terletak pada "konteks", atau bagaimana anda melaksanakan sebuah fungsi. Membandingkan bagaimana kita memanggil fungsi:
// Example 1
foobar.bar();
// Example 2
const barFunc = foobar.bar;
barFunc();
Melihat perbedaan. Pada contoh pertama, kita menentukan persis di mana bar
metode1 ini terletak pada foobar
objek:
foobar.bar();
^^^^^^
Tapi di babak kedua, kami toko metode yang menjadi variabel baru, dan menggunakan variabel tersebut untuk memanggil metode, tanpa menyatakan secara eksplisit di mana metode yang benar-benar ada, jadi kehilangan konteks:
barFunc(); // Which object is this function coming from?
Dan di situlah letak masalahnya, ketika anda menyimpan sebuah metode dalam variabel, asli informasi tentang di mana metode tersebut adalah terletak (konteks di mana metode ini dieksekusi), hilang. Tanpa informasi ini, pada saat runtime, tidak ada cara untuk JavaScript penerjemah untuk mengikat benar ini
—tanpa konteks tertentu, ini
tidak bekerja seperti yang diharapkan2.
Berikut ini's contoh Bereaksi komponen (disingkat untuk singkatnya) yang menderita ini
masalah:
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>
);
}
Tapi mengapa, dan bagaimana bagian sebelumnya berhubungan dengan ini? Hal ini karena mereka menderita sebuah abstraksi dari masalah yang sama. Jika anda melihat bagaimana Bereaksi menangani event handlers:
// 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
Jadi, ketika anda melakukan onClick={ini.handleClick}
, metode ini.handleClick
akhirnya ditugaskan untuk variabel pendengar
3. Tapi sekarang anda melihat masalah timbul—karena kita've ditugaskan ini.handleClick
untuk pendengar
, kita tidak lagi menentukan persis di mana handleClick
datang dari! Dari Bereaksi's point of view, pendengar
adalah hanya beberapa fungsi, tidak melekat pada objek apapun (atau dalam kasus ini, Bereaksi komponen contoh). Kita telah kehilangan konteks dan dengan demikian penerjemah tidak dapat menyimpulkan ini
nilai untuk menggunakan dalam handleClick
.
Anda mungkin bertanya-tanya, jika penerjemah memutuskan ini
nilai pada saat runtime, mengapa saya bisa mengikat handler sehingga tidak bekerja? Hal ini karena anda dapat menggunakan Fungsi#mengikatuntuk *jaminan* the
ininilai pada saat runtime. Hal ini dilakukan dengan pengaturan internal
iniproperti mengikat pada fungsi, yang memungkinkan untuk tidak menyimpulkan
ini`:
this.handleClick = this.handleClick.bind(this);
Ketika baris ini dieksekusi, mungkin dalam konstruktor, saat ini
ditangkap (Bereaksi komponen contoh) dan ditetapkan sebagai internal ini
mengikat yang sama sekali baru fungsi, kembali dari Fungsi#bind
. Ini akan memastikan bahwa ketika ini
sedang dihitung pada saat runtime, penafsir tidak akan mencoba untuk menyimpulkan apa-apa, tapi gunakan yang disediakan ini
nilai yang anda berikan itu.
Panah fungsi properti kelas saat ini bekerja melalui Babel berdasarkan transpilation:
handleClick = () => { /* Can use this just fine here */ }
Menjadi:
constructor() {
super();
this.handleClick = () => {}
}
ini
mereka melampirkan lingkup. Dalam hal ini, pembina
's ini
, yang menunjuk ke Bereaksi komponen contoh—sehingga memberikan anda yang benar ini
.4 1 saya gunakan "metode" untuk merujuk ke fungsi yang seharusnya terikat untuk sebuah objek, dan "fungsi" bagi mereka yang tidak.
2 Di kedua cuplikan, undefined dicatat bukan 3 karena ini
default global eksekusi konteks (jendela
bila tidak strict mode, atau yang lain undefined
) ketika itu tidak dapat ditentukan melalui konteks tertentu. Dan dalam contoh jendela.foo
tidak ada sehingga menghasilkan terdefinisi.
3 Jika anda pergi ke lubang kelinci dari bagaimana peristiwa di acara antrian dieksekusi, invokeGuardedCallback
disebut pada pendengar.
4 It's benar-benar jauh lebih rumit. Bereaksi secara internal mencoba untuk menggunakan Fungsi#menerapkanpada pendengar untuk digunakan sendiri, tapi ini tidak bekerja panah fungsi karena mereka hanya tidak mengikat
ini. Itu berarti, saat
inidalam panah fungsi adalah benar-benar dievaluasi,
inidiselesaikan setiap leksikal lingkungan masing-masing eksekusi konteks saat ini kode dari modul. Konteks eksekusi yang akhirnya memutuskan untuk memiliki
inimengikat *adalah* konstruktor, yang memiliki
ini` menunjuk ke saat ini Bereaksi komponen misalnya, yang memungkinkan untuk bekerja.
Rekomendasi saya adalah gunakan panah berfungsi sebagai sifat
class SomeClass extends React.Component {
handleClick = () => {
console.log(this); // the React Component instance
}
render() {
return (
<button onClick={this.handleClick}></button>
);
}
}
dan jangan gunakan panah berfungsi sebagai
class SomeClass extends React.Component {
handleClick(){
console.log(this); // the React Component instance
}
render() {
return (
<button onClick={()=>{this.handleClick}}></button>
);
}
}
karena kedua pendekatan ini akan menghasilkan fungsi baru setiap membuat panggilan pada kenyataannya ini berarti pointer baru versi baru dari alat peraga, daripada jika anda nanti akan peduli tentang kinerja anda dapat menggunakan Bereaksi.PureComponent atau Bereaksi.Komponen anda dapat mengganti shouldComponentUpdate(nextProps, nextState) dan dangkal memeriksa ketika alat peraga tiba
Kita perlu untuk mengikat fungsi event dengan komponen di konstruktor seperti berikut,
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
Terima kasih
Kita harus mengikat
fungsi kita dengan ini
untuk mendapatkan contoh dari fungsi di kelas. Seperti dalam contoh
<button onClick={this.sendContent.bind(this)}>Submit</button>
Ini cara ini.negara
akan berlaku objek.
Anda dapat memecahkan masalah ini mengikuti langkah-langkah berikut
Perubahan sendContent fungsi dengan
sendContent(e) {
console.log('sending input content '+this.refs.someref.value)
}
Perubahan membuat fungsi dengan
<input type="text" ref="someref" value={this.state.inputContent}
onChange={(event)=>this.changeContent(event)} />
<button onClick={(event)=>this.sendContent(event)}>Submit</button>
Anda dapat mengatasi hal ini dengan tiga cara
1.Mengikat fungsi event di constructor itu sendiri sebagai berikut
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.Mengikat ketika itu disebut
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 menggunakan Panah fungsi
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(this)
dapat memperbaiki masalah ini, dan saat ini kita bisa menggunakan 2 cara untuk mencapai hal ini jika anda don't seperti menggunakan mengikat
.
bind(this)
dalam konstruktor, sehingga ketika kita menggunakan fungsi sebagai JSX callback, konteks ini
adalah kelas itu sendiri.` kelas App1 meluas Bereaksi.Komponen { konstruktor(alat peraga) { super(alat peraga); // Jika kita komentar pada baris berikut, // kita akan mendapatkan run time error berkata
ini` adalah undefined.
ini.changeColor = ini.changeColor.bind(this);
}
changeColor(e) { e.currentTarget.gaya.backgroundColor = "#00FF00"; konsol.log(ini.alat peraga); }
render() { return (
Jika kita mendefinisikan fungsi sebagai atribut/field dari class dengan panah fungsi, kita don't perlu menggunakan bind(this)
lagi.
``
kelas App2 meluas Bereaksi.Komponen {
changeColor = e => {
e.currentTarget.gaya.backgroundColor = "#00FF00";
konsol.log(ini.alat peraga);
};
render() {
return (
Jika kita menggunakan panah berfungsi sebagai JSX callback, kita don't perlu menggunakan bind(this)
baik. Dan lebih jauh lagi, kita bisa lulus dalam parameter. Terlihat baik, isn't itu? namun kelemahan adalah kinerja yang menjadi perhatian, untuk detailnya silakan lihat ReactJS doco.
``
kelas App3 meluas Bereaksi.Komponen {
changeColor(e, colorHex) {
e.currentTarget.gaya.backgroundColor = colorHex;
konsol.log(ini.alat peraga);
}
render() {
return (
Dan saya telah menciptakan sebuah Codepen untuk demo cuplikan kode ini, semoga membantu.
jika ada yang pernah akan mencapai jawaban ini, berikut ini adalah cara untuk mengikat semua fungsi tanpa perlu mengikat mereka secara manual
dalam konstruktor():
for (let member of Object.getOwnPropertyNames(Object.getPrototypeOf(this))) {
this[member] = this[member].bind(this)
}
atau membuat fungsi ini di global.jsx file
export function bindAllFunctions({ bindTo: dis }) {
for (let member of Object.getOwnPropertyNames(Object.getPrototypeOf(dis))) {
dis[member] = dis[member].bind(dis)
}
}
dan di dalam konstruktor() menyebutnya seperti:
bindAllFunctions({ bindTo: this })
Masalah ini terjadi karena ini.changeContent
dan onClick={ini.sendContent}
tidak terikat ini contoh komponen .
Ada solusi lain (selain menggunakan bind() dalam konstruktor() ) untuk menggunakan panah fungsi ES6 yang berbagi sama leksikal lingkup kode sekitarnya dan mempertahankan ini , sehingga anda dapat mengubah kode anda di render() menjadi :
render() {
return (
<input type="text"
onChange={ () => this.changeContent() } />
<button onClick={ () => this.sendContent() }>Submit</button>
)
}
Halo jika anda ingin tidak peduli tentang mengikat diri anda panggilan fungsi. Anda dapat menggunakan 'kelas-autobind' dan import seperti itu
import autobind from 'class-autobind';
class test extends Component {
constructor(props){
super(props);
autobind(this);
}
Jangan menulis autobind sebelum super panggilan karena itu tidak akan bekerja
Dalam kasus anda ingin menyimpan mengikat dalam sintaks konstruktor, anda dapat menggunakan proposal-mengikat-operator dan mengubah kode seperti berikut :
constructor() {
this.changeContent = ::this.changeContent;
}
Bukannya :
constructor() {
this.changeContent = this.changeContent.bind(this);
}
jauh lebih sederhana, tidak perlu bind(this)
atau fatArrow
.
masalah ini terjadi setelah react15.0 ,yang event handler didn't auto mengikat komponen. jadi anda harus mengikat ini untuk komponen secara manual setiap kali event handler akan dipanggil.
ada beberapa metode untuk memecahkan masalah. tapi anda perlu untuk mengetahui metode mana yang terbaik dan mengapa? Secara umum, kami sarankan yang mengikat anda fungsi di kelas konstruktor atau menggunakan panah fungsi.
// 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} />
);
}
dua metode ini tidak akan menciptakan fungsi baru ketika komponen membuat setiap kali. jadi kami ChildComponent tidak akan reRender karena baru fungsi alat peraga perubahan, atau dapat menghasilkan masalah kinerja.
Anda menggunakan ES6 sehingga fungsi tidak akan mengikat "" konteks secara otomatis. Anda harus secara manual mengikat fungsi dengan konteks.
constructor(props) {
super(props);
this.changeContent = this.changeContent.bind(this);
}
Fungsi-fungsi kebutuhan yang mengikat dalam rangka untuk bermain dengan negara atau alat peraga dalam kegiatan penangan
Di ES5, mengikat event handler fungsi hanya dalam constructor tapi don't mengikat langsung di render. Jika anda melakukan mengikat langsung di render maka menciptakan fungsi baru setiap kali anda membuat komponen dan kembali merender. Jadi anda harus selalu mengikat dalam constructor
this.sendContent = this.sendContent.bind(this)
Di ES6, gunakan panah fungsi
Ketika anda menggunakan panah fungsi maka anda tidak perlu melakukan mengikat dan anda juga dapat menjauh dari ruang lingkup isu-isu terkait
sendContent = (event) => {
}
Alexandre Kirszenberg adalah benar, Tetapi hal lain yang penting untuk membayar perhatian , adalah di mana anda menempatkan anda mengikat. Aku telah terjebak dengan situasi selama beberapa hari(mungkin karena saya'm pemula), tapi tidak seperti orang lain, aku tahu tentang bind(Yang aku telah diterapkan sudah) jadi saya hanya tidak't mendapatkan kepala saya sekitar mengapa saya masih memiliki kesalahan-kesalahan. Ternyata bahwa aku telah mengikat dalam urutan yang salah.
Yang lain juga mungkin fakta bahwa saya memanggil fungsi dalam "ini.negara", yang tidak menyadari mengikat karena hal itu terjadi untuk menjadi di atas mengikat line,
Di bawah ini adalah apa yang saya punya(By the way ini adalah pertama saya pernah posting, Tapi saya pikir itu sangat penting, karena saya tidak't menemukan solusi di mana pun):
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"
Solusi:
mengikat
dengan nama metode yang dapat anda gunakan lemak panah fungsi sintaks ()=>{} yang mempertahankan konteks ini
.`` impor Bereaksi dari 'bereaksi'
kelas SomeClass meluas Bereaksi.Komponen { konstruktor(alat peraga) { super(alat peraga) ini.negara = { inputContent: 'startValue' } }
sendContent = (e) => { konsol.log('mengirimkan input konten ',ini.negara.inputContent); }
changeContent = (e) => { ini.setState({inputContent: e.target.nilai},()=>{ konsol.log('NEGARA:',ini.negara); }) }
render() { return (
ekspor default SomeClass
``
Solusi Lain:
Mengikat fungsi di kelas konstruktor.
Mengikat fungsi anda di BEJ Template melarikan diri kawat gigi {} {ini.code.bind(this)}