Это не может работать.
Вы получаете доступ к 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
})
Опять же, надеемся, что это поможет:)