React, ES6 - getInitialState đã được định nghĩa trên một lớp JavaScript đơn giản


115

Tôi có thành phần sau ( radioOther.jsx):

 'use strict';

 //module.exports = <-- omitted in update

   class RadioOther extends React.Component {

     // omitted in update 
     // getInitialState() {
     //    propTypes: {
     //        name: React.PropTypes.string.isRequired
     //    }
     //    return {
     //       otherChecked: false
     //   }
     // }

     componentDidUpdate(prevProps, prevState) {
         var otherRadBtn = this.refs.otherRadBtn.getDOMNode();

         if (prevState.otherChecked !== otherRadBtn.checked) {
             console.log('Other radio btn clicked.')
             this.setState({
                 otherChecked: otherRadBtn.checked,
             });
         }
     }

     onRadChange(e) {
         var input = e.target;
         this.setState({
             otherChecked: input.checked
         });
     }

     render() {
         return (
             <div>
                 <p className="form-group radio">
                     <label>
                         <input type="radio"
                                ref="otherRadBtn"
                                onChange={this.onRadChange}
                                name={this.props.name}
                                value="other"/>
                         Other
                     </label>
                     {this.state.otherChecked ?
                         (<label className="form-inline">
                             Please Specify:
                             <input
                                 placeholder="Please Specify"
                                 type="text"
                                 name="referrer_other"
                                 />
                         </label>)
                         :
                         ('')
                     }
                 </p>
             </div>
         )
     }
 };

Trước khi sử dụng ECMAScript6 tất cả đều ổn, bây giờ tôi nhận được 1 lỗi, 1 cảnh báo và tôi có một câu hỏi tiếp theo:

Lỗi: Uncaught TypeError: Không thể đọc thuộc tính 'otherChecked' của null

Cảnh báo: getInitialState đã được xác định trên RadioOther, một lớp JavaScript đơn giản. Điều này chỉ được hỗ trợ cho các lớp được tạo bằng React.createClass. Ý của bạn là định nghĩa một tài sản nhà nước thay thế?


  1. Bất cứ ai cũng có thể thấy lỗi nằm ở đâu, tôi biết đó là do câu lệnh có điều kiện trong DOM nhưng rõ ràng tôi không khai báo chính xác giá trị ban đầu của nó?

  2. Tôi có nên làm cho getInitialState tĩnh

  3. Đâu là nơi thích hợp để khai báo proptypes của tôi nếu getInitialState không đúng?

CẬP NHẬT:

   RadioOther.propTypes = {
       name: React.PropTypes.string,
       other: React.PropTypes.bool,
       options: React.PropTypes.array }

   module.exports = RadioOther;

@ssorallen, mã này:

     constructor(props) {
         this.state = {
             otherChecked: false,
         };
     }

sản xuất "Uncaught ReferenceError: this is not defined", và trong khi dưới đây sửa chữa rằng

     constructor(props) {
     super(props);
         this.state = {
             otherChecked: false,
         };
     }

nhưng bây giờ, nhấp vào nút khác bây giờ tạo ra lỗi:

Uncaught TypeError: Cannot read property 'props' of undefined


1
Sự thay đổi khác cho các lớp ES6 là các phương thức không "tự động ràng buộc" với thể hiện, nghĩa là khi bạn truyền một hàm như thế onChange={this.onRadChange}, thiskhông tham chiếu đến thể hiện khi onRadChangeđược gọi. Bạn cần liên kết các cuộc gọi lại trong renderhoặc thực hiện nó trong hàm tạo : onChange={this.onRadChange.bind(this)}.
Ross Allen

Câu trả lời:


239
  • getInitialStatekhông được sử dụng trong các lớp ES6. Thay vào đó chỉ định this.statetrong hàm tạo.
  • propTypes nên là một biến lớp tĩnh hoặc được gán cho lớp, nó không nên được gán cho các thể hiện thành phần.
  • Các phương thức thành viên không được "tự động ràng buộc" trong các lớp ES6. Đối với các phương thức được sử dụng làm cuộc gọi lại, hãy sử dụng các trình khởi tạo thuộc tính lớp hoặc gán các thể hiện ràng buộc trong hàm tạo.
export default class RadioOther extends React.Component {

  static propTypes = {
    name: React.PropTypes.string.isRequired,
  };

  constructor(props) {
    super(props);
    this.state = {
      otherChecked: false,
    };
  }

  // Class property initializer. `this` will be the instance when
  // the function is called.
  onRadChange = () => {
    ...
  };

  ...

}

Xem thêm trong tài liệu của React về Lớp ES6: Chuyển đổi hàm thành lớp


Một năm sau và bây giờ bạn có thể thấy bạn nhận được: Uncaught TypeError: Cannot read property 'bind' of undefinedlỗi Có ý tưởng nào không?
Jamie Hutber

@JamieHutber Bạn có thể tạo một câu hỏi mới với mã của bạn không? Nếu phương thức được định nghĩa trên lớp, tôi không biết tại sao bạn lại gặp lỗi đó.
Ross Allen

Cảm ơn lời đề nghị, @KennethWorden. Tôi đã mở một vấn đề cho các tài liệu React: github.com/facebook/react/issues/7746
Ross Allen

Có phải 'liên kết chúng tại chỗ' có nghĩa là sử dụng chức năng mũi tên như bạn hiển thị ở trên không? Điều đó làm việc, tất nhiên. Ồ, javascript!
jomofrodo

@jomofrodo Điều đó không rõ ràng, cảm ơn vì đã chỉ ra điều đó. Ý tôi là renderbạn có thể làm điều gì đó tương tự onClick={this.doFoo.bind(this)}, nhưng tôi cố tình không đưa nó vào mã bởi vì đó là cách liên kết kém hiệu quả nhất vì rendercó thể được gọi thường xuyên và sẽ tạo ra các chức năng mới cho mỗi cuộc gọi. Tôi sẽ loại bỏ ngôn ngữ đó khỏi câu trả lời.
Ross Allen

4

Thêm vào câu trả lời của Ross .

Bạn cũng có thể sử dụng chức năng mũi tên ES6 mới trên thuộc tính onChange

Nó tương đương về mặt chức năng với định nghĩa this.onRadChange = this.onRadChange.bind(this);trong hàm tạo nhưng theo tôi thì ngắn gọn hơn.

Trong trường hợp của bạn, nút radio sẽ giống như bên dưới.

<input type="radio"
       ref="otherRadBtn"
       onChange={(e)=> this.onRadChange(e)}
       name={this.props.name}
       value="other"/>

Cập nhật

Phương thức "ngắn gọn hơn" này kém hiệu quả hơn các tùy chọn được đề cập trong câu trả lời của @Ross Allen vì nó tạo ra một hàm mới mỗi khi render()phương thức được gọi


1
Giải pháp này đúng về mặt chức năng, nhưng nó tạo ra một Hàm mới trên mỗi cuộc gọi đến render(có thể được gọi nhiều lần). Bằng cách sử dụng một trình khởi tạo thuộc tính lớp hoặc ràng buộc trong hàm tạo, chỉ có một Hàm ràng buộc mới được tạo khi xây dựng thành phần và không có Hàm mới nào được tạo trong suốt render.
Ross Allen

1

Nếu bạn đang sử dụng thuộc tính babel-plugin-Transform-class hoặc babel-preset-giai đoạn-2 (hoặc giai đoạn-1 hoặc giai đoạn-0), bạn có thể sử dụng cú pháp này:

class RadioOther extends React.Component {

  static propTypes = {
    name: React.PropTypes.string,
    ...
  };

  state = {
      otherChecked: false,
  };

  onRadChange = () => {
    ...
  };

  ...

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.