Không thể truy cập cá thể React (this) bên trong trình xử lý sự kiện [trùng lặp]

220
user3696212 2015-04-12 02:41.

Tôi đang viết một thành phần đơn giản trong ES6 (với BabelJS) và các hàm this.setStatekhông hoạt động.

Các lỗi điển hình bao gồm một số lỗi như

Không thể đọc thuộc tính 'setState' của undefined

hoặc là

this.setState không phải là một hàm

Bạn có biết tại sao? Đây là mã:

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

19 answers

253
Alexandre Kirszenberg 2015-04-12 03:09.

this.changeContentcần phải được liên kết với cá thể thành phần thông qua this.changeContent.bind(this)trước khi được chuyển làm phần onChangehỗ trợ, nếu không thisbiến trong phần thân của hàm sẽ không tham chiếu đến cá thể thành phần mà đến window. Xem Chức năng :: ràng buộc .

Khi sử dụng React.createClassthay vì các lớp ES6, mọi phương thức không thuộc vòng đời được xác định trên một thành phần sẽ tự động được liên kết với cá thể thành phần. Xem Tự động ghi sổ .

Cần biết rằng việc ràng buộc một hàm sẽ tạo ra một hàm mới. Bạn có thể liên kết nó trực tiếp trong kết xuất, có nghĩa là một hàm mới sẽ được tạo mỗi khi thành phần hiển thị hoặc liên kết nó trong hàm tạo của bạn, hàm này sẽ chỉ kích hoạt một lần.

constructor() {
  this.changeContent = this.changeContent.bind(this);
}

vs

render() {
  return <input onChange={this.changeContent.bind(this)} />;
}

Refs được đặt trên cá thể thành phần chứ không phải trên React.refs: bạn cần thay đổi React.refs.somerefthành this.refs.someref. Bạn cũng sẽ cần liên kết sendContentphương thức với cá thể thành phần thisđể tham chiếu đến nó.

104
Kyeotic 2015-12-03 08:15.

Morhaus đúng, nhưng điều này có thể được giải quyết mà không cần bind.

Bạn có thể sử dụng một hàm mũi tên cùng với đề xuất thuộc tính lớp :

class SomeClass extends React.Component {
  changeContent = (e) => {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return <input type="text" onChange={this.changeContent} />;
  }
}

Vì hàm mũi tên được khai báo trong phạm vi của phương thức khởi tạo và vì các hàm mũi tên duy trì thistừ phạm vi khai báo của chúng, nên tất cả đều hoạt động. Nhược điểm ở đây là những chức năng này sẽ không phải là các chức năng trên nguyên mẫu, tất cả chúng sẽ được tạo lại với từng thành phần. Tuy nhiên, điều này không có nhiều nhược điểm vì bindkết quả tương tự.

56
Kaloyan Kosev 2016-12-22 12:11.

Vấn đề này là một trong những điều đầu tiên mà hầu hết chúng ta gặp phải, khi chuyển từ React.createClass()cú pháp định nghĩa thành phần sang cách mở rộng lớp ES6 React.Component.

Nó được gây ra bởi sự thiskhác biệt về bối cảnh trong React.createClass()vsextends React.Component .

Việc sử dụng React.createClass()sẽ tự động ràng buộc thisngữ cảnh (giá trị) một cách chính xác, nhưng đó không phải là trường hợp khi sử dụng các lớp ES6. Khi thực hiện theo cách ES6 (bằng cách mở rộng React.Component), thisngữ cảnh là nulltheo mặc định. Các thuộc tính của lớp không tự động liên kết với cá thể (thành phần) của lớp React.


Các phương pháp để giải quyết vấn đề này

Tôi biết tổng cộng 4 cách tiếp cận chung.

  1. Ràng buộc các hàm của bạn trong hàm tạo lớp . Được nhiều người coi là cách tiếp cận thực tiễn tốt nhất giúp tránh chạm vào JSX và không tạo một chức năng mới trên mỗi thành phần render.

    class SomeClass extends React.Component {
      constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
      }
      handleClick() {
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={this.handleClick}></button>
        );
      }
    }
    
  2. Ràng buộc các chức năng của bạn nội tuyến . Bạn vẫn có thể tìm thấy phương pháp này được sử dụng ở đây và ở đó trong một số hướng dẫn / bài báo / v.v., vì vậy điều quan trọng là bạn phải biết về nó. Nó có cùng một khái niệm như # 1, nhưng hãy lưu ý rằng việc ràng buộc một hàm sẽ tạo ra một hàm mới cho mỗi lần hiển thị lại.

    class SomeClass extends React.Component {
      handleClick() {
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={this.handleClick.bind(this)}></button>
        );
      }
    }
    
  3. Sử dụng một hàm mũi tên béo . Cho đến các hàm mũi tên, mọi hàm mới đều xác định thisgiá trị riêng của nó . Tuy nhiên, hàm arrow không tạo thisngữ cảnh riêng , vì vậy thiscó nghĩa gốc từ thể hiện thành phần React. Do đó, chúng tôi có thể:

    class SomeClass extends React.Component {
      handleClick() {
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={ () => this.handleClick() }></button>
        );
      }
    }
    

    hoặc là

    class SomeClass extends React.Component {
      handleClick = () => {
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={this.handleClick}></button>
        );
      }
    }
    
  4. Sử dụng thư viện chức năng tiện ích để tự động liên kết các chức năng của bạn . Có một vài thư viện tiện ích có sẵn, tự động thực hiện công việc cho bạn. Dưới đây là một số phổ biến, chỉ cần đề cập đến một số:

    • Autobind Decorator là một gói NPM liên kết các phương thức của một lớp với phiên bản chính xác của nó this, ngay cả khi các phương thức được tách rời. Gói sử dụng @autobindcác phương thức trước để liên kết thisvới tham chiếu chính xác đến ngữ cảnh của thành phần.

      import autobind from 'autobind-decorator';
      
      class SomeClass extends React.Component {
        @autobind
        handleClick() {
          console.log(this); // the React Component instance
        }
        render() {
          return (
            <button onClick={this.handleClick}></button>
          );
        }
      }
      

      Autobind Decorator đủ thông minh để cho phép chúng tôi liên kết tất cả các phương thức bên trong một lớp thành phần cùng một lúc, giống như cách tiếp cận số 1.

    • Class Autobind là một gói NPM khác được sử dụng rộng rãi để giải quyết vấn đề ràng buộc này. Không giống như Autobind Decorator, nó không sử dụng mẫu trang trí, mà thực sự chỉ sử dụng một hàm bên trong hàm tạo của bạn để tự động liên kết các phương thức của Thành phần với tham chiếu chính xác của this.

      import autobind from 'class-autobind';
      
      class SomeClass extends React.Component {
        constructor() {
          autobind(this);
          // or if you want to bind only only select functions:
          // autobind(this, 'handleClick');
        }
        handleClick() {
          console.log(this); // the React Component instance
        }
        render() {
          return (
            <button onClick={this.handleClick}></button>
          );
        }
      }
      

      Tái bút : Thư viện tương tự khác là React Autobind .


sự giới thiệu

Nếu tôi là bạn, tôi sẽ gắn bó với cách tiếp cận số 1. Tuy nhiên, ngay khi bạn nhận được rất nhiều liên kết trong phương thức khởi tạo lớp của mình, tôi khuyên bạn nên khám phá một trong những thư viện trợ giúp được đề cập trong cách tiếp cận số 4.


Khác

Nó không liên quan đến vấn đề bạn gặp phải, nhưng bạn không nên lạm dụng quá nhiều lời từ chối .

Xu hướng đầu tiên của bạn có thể là sử dụng refs để "làm cho mọi thứ xảy ra" trong ứng dụng của bạn. Nếu đúng như vậy, hãy dành một chút thời gian và suy nghĩ chín chắn hơn về vị trí mà trạng thái nên được sở hữu trong hệ thống phân cấp thành phần.

Đối với các mục đích tương tự, giống như mục đích bạn cần, sử dụng một thành phần được kiểm soát là cách ưu tiên. Tôi khuyên bạn nên cân nhắc sử dụng Thành phầnstate của mình . Vì vậy, bạn chỉ có thể truy cập vào các giá trị như thế này: this.state.inputContent.

8
Andrew Li 2018-08-09 20:01.

Mặc dù các câu trả lời trước đây đã cung cấp cái nhìn tổng quan cơ bản về các giải pháp (tức là liên kết, hàm mũi tên, trình trang trí thực hiện điều này cho bạn), tôi vẫn chưa tìm ra câu trả lời thực sự giải thích tại sao điều này là cần thiết — theo ý kiến ​​của tôi là gốc nhầm lẫn và dẫn đến các bước không cần thiết như ràng buộc không cần thiết và mù quáng làm theo những gì người khác làm.

this năng động

Để hiểu tình huống cụ thể này, hãy giới thiệu ngắn gọn về cách thishoạt động. Điều quan trọng ở đây là thisràng buộc thời gian chạy và phụ thuộc vào bối cảnh thực thi hiện tại. Do đó, tại sao nó thường được gọi là "ngữ cảnh" —có thông tin về bối cảnh thực thi hiện tại và tại sao bạn cần phải ràng buộc là do bạn lỏng lẻo "ngữ cảnh". Nhưng hãy để tôi minh họa vấn đề bằng một đoạn mã:

const foobar = {
  bar: function () {
    return this.foo;
  },
  foo: 3,
};
console.log(foobar.bar()); // 3, all is good!

Trong ví dụ này, chúng tôi nhận được 3, như mong đợi. Nhưng hãy lấy ví dụ này:

const barFunc = foobar.bar;
console.log(barFunc()); // Uh oh, undefined!

Có thể bất ngờ khi thấy rằng nó ghi nhật ký không xác định — nó đã 3đi đâu? Câu trả lời nằm ở "ngữ cảnh" , hoặc cách bạn thực thi một hàm. So sánh cách chúng tôi gọi các hàm:

// Example 1
foobar.bar();
// Example 2
const barFunc = foobar.bar;
barFunc();

Chú ý sự khác biệt. Trong ví dụ đầu tiên, chúng tôi đang chỉ định chính xác vị trí của barphương thức 1 — trên foobarđối tượng:

foobar.bar();
^^^^^^

Nhưng trong lần thứ hai, chúng tôi lưu trữ phương thức vào một biến mới và sử dụng biến đó để gọi phương thức, mà không nói rõ nơi phương thức thực sự tồn tại, do đó làm mất ngữ cảnh :

barFunc(); // Which object is this function coming from?

Và vấn đề nằm ở đó, khi bạn lưu trữ một phương thức trong một biến, thông tin ban đầu về vị trí của phương thức đó (bối cảnh mà phương thức đang được thực thi), sẽ bị mất. Nếu không có thông tin này, trong thời gian chạy, không có cách nào để trình thông dịch JavaScript liên kết đúng this— không có ngữ cảnh cụ thể, thiskhông hoạt động như mong đợi 2 .

Liên quan đến React

Dưới đây là một ví dụ về một thành phần React (viết tắt cho ngắn gọn) đang gặp sự thiscố:

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

Nhưng tại sao, và làm thế nào phần trước liên quan đến điều này? Điều này là do họ mắc phải một vấn đề trừu tượng của cùng một vấn đề. Nếu bạn xem cách React xử lý các trình xử lý sự kiện :

// 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

Vì vậy, khi bạn thực hiện onClick={this.handleClick}, phương thức this.handleClickcuối cùng được gán cho biến listener3 . Nhưng bây giờ bạn gặp sự cố phát sinh-vì chúng ta đã gán this.handleClickcho listener, chúng tôi không còn xác định chính xác nơi handleClickđến từ! Theo quan điểm của React, listenerchỉ là một số hàm, không được gắn với bất kỳ đối tượng nào (hoặc trong trường hợp này là thể hiện thành phần React). Chúng tôi đã mất ngữ cảnh và do đó trình thông dịch không thể suy ra một thisgiá trị để sử dụng bên trong handleClick .

Tại sao ràng buộc hoạt động

Bạn có thể tự hỏi, nếu trình thông dịch quyết định thisgiá trị trong thời gian chạy, tại sao tôi có thể ràng buộc trình xử lý để nó hoạt động ? Đây là bởi vì bạn có thể sử dụng Function#bindđể đảm bảo các thisgiá trị tại thời gian chạy. Điều này được thực hiện bằng cách đặt thuộc thistính ràng buộc nội bộ trên một hàm, cho phép nó không suy ra this:

this.handleClick = this.handleClick.bind(this);

Khi dòng này được thực thi, có lẽ trong hàm khởi tạo, dòng điện thisđược ghi lại (thể hiện thành phần React) và được đặt làm thisràng buộc bên trong của một hàm hoàn toàn mới, được trả về từ đó Function#bind. Điều này đảm bảo rằng thời điểm thisđang được tính toán trong thời gian chạy, trình thông dịch sẽ không cố gắng suy luận bất kỳ điều gì, mà sử dụng thisgiá trị được cung cấp mà bạn đã cung cấp cho nó.

Tại sao thuộc tính hàm mũi tên hoạt động

Các thuộc tính của lớp hàm mũi tên hiện hoạt động thông qua Babel dựa trên sự chuyển đổi:

handleClick = () => { /* Can use this just fine here */ }

Trở thành:

constructor() {
  super();
  this.handleClick = () => {}
}

Và điều này hoạt động do thực tế, các hàm mũi tên không ràng buộc cái này của riêng chúng, mà lấy thisphạm vi bao quanh của chúng. Trong trường hợp này, constructor's this, trỏ đến cá thể thành phần React - do đó sẽ cho bạn đúng this. 4


1 Tôi sử dụng "method" để tham chiếu đến một hàm được cho là được liên kết với một đối tượng và "function" cho những đối tượng không.

2 Trong đoạn mã thứ hai, undefined được ghi thay vì 3 vì thismặc định là bối cảnh thực thi chung ( windowkhi không ở chế độ nghiêm ngặt, hoặc nếu không undefined) khi không thể xác định nó thông qua ngữ cảnh cụ thể. Và trong ví dụ window.foonày không tồn tại do đó tạo ra không xác định.

3 Nếu bạn xem xét cách các sự kiện trong hàng đợi sự kiện được thực thi, invokeGuardedCallbacksẽ được gọi trên trình nghe.

4 Nó thực sự phức tạp hơn rất nhiều . React nội bộ cố gắng sử dụng Function#applytrên các trình nghe để sử dụng riêng, nhưng điều này không hoạt động với các hàm mũi tên vì chúng chỉ đơn giản là không ràng buộc this. Điều đó có nghĩa là, khi thisbên trong hàm mũi tên được đánh giá thực sự, thisnó được giải quyết theo từng môi trường từ vựng của mỗi ngữ cảnh thực thi của mã hiện tại của mô-đun. Bối cảnh thực thi cuối cùng đã giải quyết để có thisràng buộc phương thức khởi tạo, có một thistrỏ đến cá thể thành phần React hiện tại, cho phép nó hoạt động.

2
Liju Kuriakose 2017-09-13 23:43.

Bạn có thể giải quyết vấn đề này bằng ba cách

1. Tìm hàm sự kiện trong chính hàm tạo như sau

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.Bind khi nó được gọi

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. bằng cách sử dụng các hàm mũi tên

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
1
Liju Kuriakose 2017-08-21 23:27.

Chúng ta cần liên kết hàm sự kiện với thành phần trong hàm tạo như sau,

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

Cảm ơn

1
Ivan Mjartan 2017-12-15 03:25.

Đề xuất của tôi là sử dụng các hàm mũi tên làm thuộc tính

class SomeClass extends React.Component {
  handleClick = () => {
    console.log(this); // the React Component instance
  }
  render() {
    return (
      <button onClick={this.handleClick}></button>
    );
  }
}

và không sử dụng các hàm mũi tên như

class SomeClass extends React.Component {
      handleClick(){
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={()=>{this.handleClick}}></button>
        );
      }
    }

bởi vì cách tiếp cận thứ hai sẽ tạo ra hàm mới mỗi lần gọi kết xuất trên thực tế, điều này có nghĩa là con trỏ mới phiên bản mới của đạo cụ, hơn là nếu sau này bạn quan tâm đến hiệu suất, bạn có thể sử dụng React.PureComponent hoặc trong React.Component bạn có thể ghi đè nênComponentUpdate (nextProps, nextState) và kiểm tra nông khi các đạo cụ đến

1
azmul hossain 2018-02-06 21:24.

Bạn có thể giải quyết vấn đề này theo các bước sau

Thay đổi chức năng sendContent bằng

 sendContent(e) {
    console.log('sending input content '+this.refs.someref.value)
  }

Thay đổi chức năng kết xuất bằng

<input type="text" ref="someref" value={this.state.inputContent} 
          onChange={(event)=>this.changeContent(event)} /> 
   <button onClick={(event)=>this.sendContent(event)}>Submit</button>
1
Mustkeem K 2018-07-09 21:05.

Chúng ta phải bindhàm của chúng ta với thisđể có được thể hiện của hàm trong lớp. Ví dụ như vậy

<button onClick={this.sendContent.bind(this)}>Submit</button>

Cách này this.statesẽ là đối tượng hợp lệ.

1
coder 2019-11-23 14:48.

nếu ai đó sẽ đạt được câu trả lời này, đây là một cách để liên kết tất cả các chức năng mà không cần phải ràng buộc chúng theo cách thủ công

trong hàm tạo ():

for (let member of Object.getOwnPropertyNames(Object.getPrototypeOf(this))) {
    this[member] = this[member].bind(this)
}

hoặc tạo hàm này trong tệp global.jsx

export function bindAllFunctions({ bindTo: dis }) {
for (let member of Object.getOwnPropertyNames(Object.getPrototypeOf(dis))) {
    dis[member] = dis[member].bind(dis)
    }
}

và trong hàm tạo () của bạn, hãy gọi nó như sau:

bindAllFunctions({ bindTo: this })
0
Bassam Rubaye 2016-06-26 19:51.

Sự cố này đang xảy ra bởi vì this.changeContentonClick={this.sendContent}không bị ràng buộc với điều này của phiên bản thành phần.

Có một giải pháp khác (Ngoài việc sử dụng bind () trong constructor ()) để sử dụng các hàm mũi tên của ES6 có cùng phạm vi từ vựng của mã xung quanh và duy trì điều này , vì vậy bạn có thể thay đổi mã của mình trong render () thành là :

render() {
    return (

        <input type="text"
          onChange={ () => this.changeContent() } /> 

        <button onClick={ () => this.sendContent() }>Submit</button>

    )
  }
0
Florent Giraud 2017-04-13 23:36.

Xin chào nếu bạn không muốn quan tâm đến việc ràng buộc bản thân lời gọi hàm của bạn. Bạn có thể sử dụng 'class-autobind' và nhập nó như vậy

import autobind from 'class-autobind';

class test extends Component {
  constructor(props){
  super(props);
  autobind(this);
}

Đừng viết tự động trước khi có cuộc gọi siêu cấp vì nó sẽ không hoạt động

0
ZEE 2017-07-06 23:00.

Trong trường hợp bạn muốn giữ liên kết trong cú pháp của hàm tạo, bạn có thể sử dụng toán tử đề xuất-ràng buộc và chuyển đổi mã của mình như sau:

constructor() {
  this.changeContent = ::this.changeContent;
}

Thay vì :

constructor() {
  this.changeContent = this.changeContent.bind(this);
}

đơn giản hơn nhiều, không cần bind(this)hoặc fatArrow.

0
jack.lin 2018-01-11 03:30.

sự cố này xảy ra sau react15.0, trình xử lý sự kiện nào không tự động liên kết với thành phần. vì vậy bạn phải liên kết điều này với thành phần theo cách thủ công bất cứ khi nào trình xử lý sự kiện sẽ được gọi.


có một số phương pháp để giải quyết vấn đề. nhưng bạn cần biết phương pháp nào là tốt nhất và tại sao? Nói chung, chúng tôi khuyên bạn nên liên kết các hàm của bạn trong hàm tạo lớp hoặc sử dụng hàm mũi tên.

// 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} /> 
        );
      }

hai phương thức này sẽ không tạo một hàm mới khi thành phần này luôn hiển thị. vì vậy ChildComponent của chúng tôi sẽ không reRender do các đạo cụ chức năng mới thay đổi, hoặc có thể gây ra vấn đề về hiệu suất.

0
Niraj Raskoti 2018-08-14 18:57.

Bạn đang sử dụng ES6 nên các hàm sẽ không tự động liên kết với ngữ cảnh "này". Bạn phải tự ràng buộc chức năng với ngữ cảnh.

constructor(props) {
  super(props);
  this.changeContent = this.changeContent.bind(this);
}
0
Hemadri Dasari 2018-08-18 15:28.

Các chức năng của bạn cần ràng buộc để chơi với trạng thái hoặc đạo cụ trong trình xử lý sự kiện

Trong ES5, ràng buộc các hàm xử lý sự kiện của bạn chỉ trong hàm tạo nhưng không ràng buộc trực tiếp trong kết xuất. Nếu bạn thực hiện ràng buộc trực tiếp trong kết xuất thì nó sẽ tạo một hàm mới mỗi khi thành phần của bạn hiển thị và kết xuất. Vì vậy, bạn nên luôn ràng buộc nó trong hàm tạo

this.sendContent = this.sendContent.bind(this)

Trong ES6, sử dụng các hàm mũi tên

Khi bạn sử dụng các hàm mũi tên thì bạn không cần phải thực hiện ràng buộc và bạn cũng có thể tránh xa các vấn đề liên quan đến phạm vi

sendContent = (event) => {

}
0
Ebe 2018-09-23 02:38.

Alexandre Kirszenberg đúng, Nhưng một điều quan trọng khác cần chú ý, là nơi bạn đặt ràng buộc của mình. Tôi đã bị mắc kẹt với một tình huống trong nhiều ngày (có thể vì tôi là người mới bắt đầu), nhưng không giống như những người khác, tôi biết về ràng buộc (mà tôi đã áp dụng rồi) vì vậy tôi chỉ không thể hiểu tại sao tôi vẫn gặp phải lỗi. Hóa ra là tôi đã ràng buộc sai thứ tự.

Một điều khác cũng có lẽ là thực tế là tôi đang gọi hàm trong "this.state", hàm này không biết về ràng buộc vì nó tình cờ nằm ​​trên đường ràng buộc,

Dưới đây là những gì tôi đã có (Nhân tiện đây là bài đăng đầu tiên của tôi, Nhưng tôi nghĩ nó rất quan trọng, vì tôi không thể tìm thấy giải pháp nào khác ở đâu):

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"
0
khizer 2019-05-04 12:25.

Giải pháp:

  1. Không có ràng buộc rõ ràng, bindvới tên phương thức, bạn có thể sử dụng cú pháp hàm mũi tên béo () => {} duy trì ngữ cảnh của this.
import React from 'react'

class SomeClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      inputContent: 'startValue'
    }
  }

  sendContent = (e) => {
    console.log('sending input content ',this.state.inputContent);
  }

  changeContent = (e) => {
    this.setState({inputContent: e.target.value},()=>{
      console.log('STATE:',this.state);
    })
  } 

  render() {
    return (
      <div>
        <h4>The input form is here:</h4>
        Title: 
        <input type="text" value={this.state.inputContent} 
          onChange={this.changeContent} /> 
        <button onClick={this.sendContent}>Submit</button>
      </div>
    )
  }
}

export default SomeClass

Các giải pháp khác:

  1. Ràng buộc các hàm của bạn trong hàm tạo lớp.

  2. Liên kết các hàm của bạn trong dấu ngoặc nhọn thoát Mẫu JSX {} {this.methodName.bind (this)}

0
Eric Tan 2019-06-28 15:22.

bind(this)có thể khắc phục sự cố này và ngày nay chúng ta có thể sử dụng 2 cách khác để đạt được điều này nếu bạn không thích sử dụng bind.

1) Theo cách truyền thống, chúng ta có thể sử dụng bind(this)trong hàm tạo, để khi chúng ta sử dụng hàm dưới dạng lệnh gọi lại JSX, ngữ cảnh của chính thislà lớp.

class App1 extends React.Component {
  constructor(props) {
    super(props);
    // If we comment out the following line,
    // we will get run time error said `this` is undefined.
    this.changeColor = this.changeColor.bind(this);
  }

  changeColor(e) {
    e.currentTarget.style.backgroundColor = "#00FF00";
    console.log(this.props);
  }

  render() {
    return (
      <div>
        <button onClick={this.changeColor}> button</button>
      </div>
    );
  }
}

2) Nếu chúng ta định nghĩa hàm là một thuộc tính / trường của lớp với hàm mũi tên, chúng ta không cần sử dụng bind(this)thêm nữa.

class App2 extends React.Component {
  changeColor = e => {
    e.currentTarget.style.backgroundColor = "#00FF00";
    console.log(this.props);
  };
  render() {
    return (
      <div>
        <button onClick={this.changeColor}> button 1</button>
      </div>
    );
  }
}

3) Nếu chúng ta sử dụng hàm arrow làm lệnh gọi lại JSX, chúng ta cũng không cần sử dụng bind(this). Và xa hơn nữa, chúng ta có thể chuyển các tham số vào. Có vẻ tốt, phải không? nhưng hạn chế của nó là mối quan tâm về hiệu suất, để biết chi tiết, vui lòng tham khảo ReactJS doco .

class App3 extends React.Component {
  changeColor(e, colorHex) {
    e.currentTarget.style.backgroundColor = colorHex;
    console.log(this.props);
  }
  render() {
    return (
      <div>
        <button onClick={e => this.changeColor(e, "#ff0000")}> button 1</button>
      </div>
    );
  }
}

Và tôi đã tạo một Codepen để demo các đoạn mã này, hy vọng nó sẽ hữu ích.

Related questions

MORE COOL STUFF

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett đã bất chấp những lời khuyên hẹn hò điển hình khi cô gặp chồng mình.

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Michael Sheen là một diễn viên phi lợi nhuận nhưng chính xác thì điều đó có nghĩa là gì?

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Ngôi sao của Hallmark Colin Egglesfield chia sẻ về những cuộc gặp gỡ với người hâm mộ ly kỳ tại RomaDrama Live! cộng với chương trình INSPIRE của anh ấy tại đại hội.

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Bạn sẽ phải phủi sạch đầu đĩa Blu-ray hoặc DVD để xem tại sao Northern Exposure trở thành một trong những chương trình nổi tiếng nhất của thập niên 90.

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

8 công dụng tuyệt vời của Baking Soda và Giấm

8 công dụng tuyệt vời của Baking Soda và Giấm

Bạn biết đấy, hai sản phẩm này là nguồn điện để làm sạch, riêng chúng. Nhưng cùng với nhau, chúng có một loạt công dụng hoàn toàn khác.

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Thủy điện rất cần thiết cho lưới điện của Hoa Kỳ, nhưng nó chỉ tạo ra năng lượng khi có nước di chuyển. Bao nhiêu nhà máy thủy điện có thể gặp nguy hiểm khi các hồ và sông cạn kiệt?

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Tóc tỉa từ các tiệm và các khoản quyên góp cá nhân có thể được tái sử dụng như những tấm thảm thấm dầu và giúp bảo vệ môi trường.

Một thương hiệu kế thừa khác có được cuộc sống mới khi những người chủ mới của Black Opal có được Hội chợ thời trang

Một thương hiệu kế thừa khác có được cuộc sống mới khi những người chủ mới của Black Opal có được Hội chợ thời trang

Desiree Rogers, trái, và Cheryl Mayberry McKissack Chuyển sang, Fenty Beauty và Pat McGrath, có một đế chế làm đẹp mới do phụ nữ làm chủ đang trỗi dậy. Sau thương vụ mua lại mỹ phẩm Black Opal vào tháng 9, đội ngũ quyền lực của Giám đốc điều hành công ty Desiree Rogers và Chủ tịch Cheryl Mayberry McKissack đã thông báo mua lại thương hiệu làm đẹp tiên phong Fashion Fair từ người sáng lập Johnson Publishing Company (JPC).

Ngoài việc trở nên vô nghĩa, các bên bộc lộ giới tính giờ đây đã trở nên chết người

Ngoài việc trở nên vô nghĩa, các bên bộc lộ giới tính giờ đây đã trở nên chết người

Đối với những người có quá nhiều thời gian, tiệc tiết lộ giới tính là một cách thú vị để không cần áp đặt những định kiến ​​hạn chế lên thai nhi trước một đối tượng bạn bè giả vờ quan tâm một cách lịch sự. Tuy nhiên, việc chỉ dựa vào những chiếc bánh nướng có màu nhân tạo để biểu thị một tiếng hoo-ha hoặc một đứa trẻ đi tè đã trở nên xa xỉ trong các bậc cha mẹ trên Instagram.

Kirstjen Nielsen đang cố gắng đổi mới bản thân với tư cách là một người phụ nữ 'nói ra sự thật cho sức mạnh'

Kirstjen Nielsen đang cố gắng đổi mới bản thân với tư cách là một người phụ nữ 'nói ra sự thật cho sức mạnh'

Hôm thứ Tư, cựu Bộ trưởng An ninh Nội địa Kirstjen Nielsen vì một lý do nào đó đã được đưa ra một diễn đàn để phát biểu tại Hội nghị thượng đỉnh Những người phụ nữ quyền lực nhất của Fortune. Và có thể đoán trước được, người phụ nữ giám sát các nỗ lực (đang diễn ra) của chính quyền Trump nhằm chia cắt các gia đình ở biên giới đã sử dụng thời gian của mình như một cơ hội để tự bảo vệ mình và tự nhận mình là người — và hãy hít thở sâu ở đây — “đã nói sự thật với quyền lực.

Toyota Racing Development sẽ cho ra mắt Supra 3000GT Concept, Massive Wing vào tháng tới

Toyota Racing Development sẽ cho ra mắt Supra 3000GT Concept, Massive Wing vào tháng tới

Vì thế hệ mới nhất của chiếc xe điều chỉnh được yêu thích trên thế giới hiện đã có mặt tại đây, nên chỉ có điều kiện là Toyota Racing Development sẽ đưa phiên bản Supra thế hệ thứ năm sửa đổi của riêng mình đến SEMA vào tháng tới. Toyota đã cho chúng tôi một gợi ý về những gì sẽ xảy ra trong tuần này: một chiếc Concept GR Supra 3000GT hiện đại.

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Rothschild's luggage got lost, but luckily she has an incredible closet to shop: Sister Paris Hilton's!

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa. Từ Hollywood đến New York và mọi nơi ở giữa, hãy xem các ngôi sao yêu thích của bạn đang làm gì!

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

Các nhà điều tra đang xem xét liệu nhóm và nghi phạm có biết nhau trước vụ tấn công hay không

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Vụ kiện, nêu tên một số học khu, lập luận rằng dự luật "Không nói đồng tính" được ban hành gần đây của Florida "có hiệu quả im lặng và xóa bỏ học sinh và gia đình LGBTQ +"

Đường băng hạ cánh

Đường băng hạ cánh

Cuối hè đầu thu là mùa hoài niệm. Những chiếc đèn đường chiếu ánh sáng của chúng qua những con đường đẫm mưa, và những chiếc lá dưới chân - màu đỏ cam tắt trong bóng chạng vạng - là lời nhắc nhở về những ngày đã qua.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Vào năm 2021, tôi khuyến khích bạn suy nghĩ lại mọi thứ bạn biết về khách hàng mà bạn phục vụ và những câu chuyện bạn kể cho họ. Lùi lại.

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Vào ngày sinh nhật thứ 9 của Felix The Cat, tôi nhớ về một trong những mất mát lớn nhất trong cuộc đời trưởng thành của tôi - Sophie của tôi vào năm 2013. Tôi đã viết bài luận này và chia sẻ nó trên nền tảng này một thời gian ngắn vào năm 2013.

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Tôi ghét từ "tàu đắm". Mọi người cảm thấy thoải mái trong la bàn đạo đức của riêng mình, và khi làm như vậy, họ thấy mình vượt qua sự phán xét.

Language