Я переместил функцию за пределы класса и сделал const.Теперь функция не работает - PullRequest
0 голосов
/ 07 февраля 2019

Я переместил функцию addONe за пределы класса Счетчик .После этого функция addOne больше не работает, но с другой стороны я не получаю никакой ошибки.У меня вопрос, что я сделал не так, что const addOne не работает?

import React from 'react';

const addOne = () => {
        this.setState((prevState) => {
            return {
                count: prevState.count + 1
            }
        })
    }


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


    // addOne() {
    //     this.setState((prevState) => {
    //         return {
    //             count: prevState.count + 1
    //         }
    //     })
    // }

    minusOne() {
        this.setState((prevState) => {
            return {
                count: prevState.count - 1
            }
        })
    }

    reset() {
        this.setState(() => {
            return {
               count: 0// count: 0
            }
        })
    }

    render() {
        return (
            <div>
                <h1>Count: {this.state.count}</h1>
                <button onClick={this.addOne}>+1</button>
                <button onClick={this.minusOne}>-1</button>
                <button onClick={this.reset}>reset</button>
            </div>
        )
    } 
}

1 Ответ

0 голосов
/ 07 февраля 2019

Это не может работать.

Вы получаете доступ к this.setState внутри своей функции, но у вас нет никакого метода setState в вашей области видимости, потому что он соответствует классу React.Component.

Реальный вопрос: почему вы хотите исключить из класса функцию addOne?

Редактировать из-за вашего комментария

Если вы учитесь, вам нужно большетехническое объяснение:)

Во-первых, вам нужно получить доступ к методу setState класса React.Component вне его, в вашей функции addOne.Нам нужно связать с этой функцией контекст, в котором существует this.setState.Что может быть лучше контекста самого компонента?

Давайте обновим метод рендеринга, заменив эту строку:

<button onClick={this.addOne}>+1</button>

на следующую:

<button onClick={addOne.bind(this)}>+1</button>

Что здесь происходит?Функция addOne получает внешний контекст (в данном случае this).Этот контекст будет использоваться как ключевое слово this внутри функции.Технически, связывание другого контекста создает новую ограниченную функцию, но это другой вопрос, который нас здесь не волнует.

Если вы попробуете это небольшое редактирование, оно все равно не будет работать.

Этопотому что вы объявляете addOne как выражение лямбда-функции.В ES6 лямбда-функции не могут иметь другие связанные контексты.

Фактически, если вы преобразуете свой addOne из выражения лямбда-функции в объявление функции, например:

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

... вы увидите, что увеличение работает правильно:)

Надеюсь, это поможет вам понять, что здесь происходит.

Сохранение синтаксиса ES6

Теперь использование лямбда-выражений функции ES6 не является невозможным, оно просто немного смещает ту же проблему.Мы не можем связать другой контекст, но мы можем сохранить его, вызывая метод, который находится или имеет правильный контекст.

Например, мы можем преобразовать выражение функции addOne в функцию более высокого порядка, которая принимаетsetState и верните нужный обработчик клика:

const addOne = setState => () =>
  setState(prevState => ({
    count: prevState.count + 1
  }))

Теперь, в методе рендеринга, мы можем использовать его следующим образом:

<button onClick={addOne(this.setState)}>+1</button>

, передавая setStateв качестве ссылки на функцию.

Теперь тонкая проблема заключается в том, что setState внутри функции addOne не имеет своего исходного контекста!

Мы можем решить это с помощью:

<button onClick={addOne(this.setState.bind(this))}>+1</button>

Редактировать из-за вашего последнего комментария

Эти синтаксисы ведут себя точно так же:

const addOne = setState => () =>
  setState(prevState => ({
    count: prevState.count + 1
  }))

const addOne = setState => () =>
  setState(prevState => {
    return { count: prevState.count + 1 }
  })

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

Это означает, что лямбда-функция может быть такой короткой, как:

const five = () => 5
// five() returns immediate value 5

Сказалв: когда у вас есть:

prevState => {
  return { count: prevState.count + 1 }
}

вы создаете тело с одним оператором, который возвращает простой объект.

Видите ли вы сходство?Вы делаете то же самое: имеете одно утверждение, которое возвращает что-то.

Первое, что может прийти вам на ум, - это переписать его, пропустив ключевое слово return, например:

prevState => {
  count: prevState.count + 1
}

Но это не сработает.Это даст вам синтаксическую ошибку из-за символа двоеточия, которого там быть не должно.Этого не должно быть, потому что, если тело выражения лямбда-функции определено как блок (заключая все в {}), предполагается, что оно имеет более одного оператора и, возможно, ключевое слово return.

Чтобы заставить его работать, нам нужно обработать определение простого объекта как единый оператор, и мы делаем это, заключив его в круглые скобки, например:

prevState => ({
  count: prevState.count + 1
})

Опять же, надеемся, что это поможет:)

...