我将一个函数移到 class 之外并制作了 const。现在该功能不起作用

I moved a function outside the class and made const. Now the function does not work

我将函数 addONe 移到了 class Counter 之外。执行此操作后,函数 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>
        )
    } 
}

它不能工作。

您正在函数内部访问 this.setState,但您的范围内没有任何 setState 方法,因为它是 React.Component class 的专有方法.

真正的问题是:为什么要移出 class 和 addOne 功能?

根据您的评论进行编辑

如果你正在学习,你需要一个更技术性的解释:)

首先,您需要在 addOne 函数中访问 React.Component class 的 setState 方法。我们需要将 this.setState 存在的上下文绑定到此函数。还有什么比组件本身的上下文更好?

让我们更新渲染方法来替换这一行:

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

这个:

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

这里发生了什么?函数 addOne 正在接收外部上下文(在本例中为 this)。此上下文将用作函数内的 this 关键字。从技术上讲,绑定另一个上下文会创建一个新的有界函数,但这是我们在这里不关心的另一件事。

如果您尝试这个小小的修改,它仍然不起作用。

那是因为您将 addOne 声明为 lambda 函数表达式。在 ES6 中,lambda 函数不能绑定其他上下文。

事实上,如果将 addOne 从 lambda 函数表达式转换为函数声明,如下所示:

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

...您会看到增加的效果正常:)

希望它能帮助您了解这里发生的事情。

保持 ES6 语法

现在,使用 ES6 lambda 函数表达式并非不可能,它只是把同样的问题稍微移到一边。我们不能绑定另一个上下文,但我们可以在它上面保持闭包,调用驻留或具有正确上下文的方法。

例如,我们可以将 addOne 函数表达式转换为高阶函数,它采用 setState 和 return 您需要的点击处理程序:

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

现在,在render方法中,我们可能会想这样使用它:

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

setState 作为函数引用传递。

现在的微妙问题是 addOne 函数中的 setState 没有原始上下文绑定!

我们可以这样解决:

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

它们的工作方式相同,因为对于 lambda 函数表达式,如果您将单个语句作为函数的主体,则该语句的计算结果会自动 returned。

这意味着 lambda 函数可以短至:

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

说,当你有:

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

您正在用一条语句创建主体,return是一个普通对象。

你看到相似之处了吗?你在做同样的事情:有一个声明 returns something.

您可能首先想到的是重写它,省略 return 关键字,例如:

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

但这行不通。由于不应该存在的冒号字符,它会给您一个语法错误。它不应该存在,因为如果 lambda 函数表达式主体被定义为一个块(用 {} 包装所有内容),它应该有多个语句,也许还有一个 return 关键字。

为了使其工作,我们需要将普通对象定义视为单个语句,我们通过将其包装在圆括号中来实现,例如:

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

再次希望对您有所帮助:)