2017-01-26 4 views
2

Попытка выяснить основы Реагирования.React - Почему привязка этого не требуется в этом примере?

Глядя на второй пример на этой странице: https://facebook.github.io/react/ Я вижу, что функция tick() задает состояние класса Timer, увеличивая предыдущее значение на единицу.

class Timer extends React.Component { 
    constructor(props) { 
    super(props); 
    this.state = {secondsElapsed: 0}; 
    } 

    tick() { 
    this.setState((prevState) => ({ 
     secondsElapsed: prevState.secondsElapsed + 1 
    })); 
    } 

    componentDidMount() { 
    this.interval = setInterval(() => this.tick(), 1000); 
    } 

    componentWillUnmount() { 
    clearInterval(this.interval); 
    } 

    render() { 
    return (
     <div>Seconds Elapsed: {this.state.secondsElapsed}</div> 
    ); 
    } 
} 

ReactDOM.render(<Timer />, mountNode); 

Однако, когда я пытался реализовать свой собственный простой класс счетчика, это не удалось, и я получил ошибку консоли говоря Не удается прочитать свойство SetState неопределенной.

class Counter extends React.Component { 
    constructor(props) { 
     super(props); 
     this.state = {count: 0}; 
    } 

    increment(prevState) { 
     this.setState((prevState) => ({ 
      count: prevState.count + 1 
     })); 
    } 

    render() { 
    return (
      <div className="main"> 
       <button onClick={this.increment}>{this.state.count}</button> 
      </div> 
    ) 
    } 
} 

Некоторые Googling показывает, что я должен связать это с функцией приращения. Но почему это не было необходимо в первом примере, который я видел? Я скопировал код в CodePen, и он отлично справился с React 15.3.1. Я не могу найти ничего похожего на привязку в этом примере. Только после того, как я добавил код привязки в конструкторе, в моем примере все стало работать.

class Counter extends React.Component { 
    constructor(props) { 
     super(props); 
     this.state = {count: 0}; 

     // THIS ONE LINE FIXED THE ISSUE 
     this.increment = this.increment.bind(this); 
    } 

    increment(prevState) { 
     this.setState((prevState) => ({ 
     count: prevState.count + 1 
    })); 
    } 

    render() { 
    return (
      <div className="main"> 
       <button onClick={this.increment}>{this.state.count}</button> 
      </div> 
    ) 
    } 
} 

ответ

11

Отвечая на ваш вопрос: первый пример использует arrow functions, который автоматически выполняет context binding. Из документов:

Функция стрелки не создает свой собственный контекст, поэтому у этого есть его исходное значение из окружающего контекста.

Действительно, есть несколько способов связывания в React:

1) вы можете bind все функции в конструкторе, как ты сказал:

constructor(props) { 
    /* ... */ 
    this.increment = this.increment.bind(this); 
} 

2) вызывать обратные вызовы с функциями стрелок :

<button onClick={(e) => this.increment(e)}> 

3) добавить .bind в конце справки метода каждого раз, когда вы установите его в качестве обратного вызова, например:

<button onClick={this.increment.bind(this)}> 

4) В классе, определить метод с функциями стрелок:

increment = (e) => { 
    /* your class function defined as ES6 arrow function */ 
} 

/* ... */ 

<button onClick={this.increment}> 

Для того, чтобы использовать этот синтаксис с Бабелем, вы должны включите это plugin или используйте предустановленную stage-2.

+0

Итак, основываясь на том, что я прочитал, если я называю this.increment() без использования функции стрелки, «это» становится связанным с глобальным объектом. Это верно? Я также понял, что вместо Adam

+2

* Я также понял, что я поставил обратный вызов как {this.increment} вместо {this.increment()} * Вы не должны помещать круглые скобки. Вы должны передать только ссылку: если вы поместите скобки, вы вызовете метод и передадите возврат в скобки. – mrlew

+2

Если возможно, я предлагаю прочитать [this] (https://github.com/getify/You-Dont-Know-JS/tree/master/this%20%26%20object%20prototypes). Вы также можете проверить ссылку [this] (https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Operators/this). – mrlew

1

Если вы внимательно посмотрите, как функция tick() была вызвана в вашем первом примере, вы поймете, что привязка была указана для нее, когда она вызывается с использованием arrow functions. Если вы будете делать то же самое для функции приращения, это также сработает. Это просто разные способы привязки функций.

Так, как и было задано, это не то, что в первом примере привязка не указана, а вторая требуется, а в обоих случаях вы связываете только то, что способ привязки отличается для обоих случаев.

class Counter extends React.Component { 
 
    constructor(props) { 
 
     super(props); 
 
     this.state = {count: 0}; 
 

 
     
 
     
 
    } 
 

 
    increment(prevState) { 
 
     this.setState((prevState) => ({ 
 
     count: prevState.count + 1 
 
    })); 
 
    } 
 

 
    render() { 
 
    return (
 
      <div className="main"> 
 
       <button onClick={() => this.increment()}>{this.state.count}</button> 
 
      </div> 
 
    ) 
 
    } 
 
} 
 

 
ReactDOM.render(<Counter/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<div id="app"></div>