javascript - "Good"如何在 React 中更新状态(从之前的值)

标签 javascript reactjs arrow-functions readability state-management

来自 react 文档

从文档( https://reactjs.org/docs/handling-events.html )我可以看到通过箭头功能处理开关按钮更改,例如:

handleClick() {
  this.setState(prevState => ({
    isToggleOn: !prevState.isToggleOn
  }));
}

这里(对我来说)重要的是,新的状态值是从其先前的状态值派生的。 如果我是对的,则行为与(没有箭头功能)相同:

handleClick() {     
    this.setState(function (prevState){
      return {isToggleOn: !prevState.isToggleOn}
    });
}

甚至根本没有功能:

handleClick() {
  this.setState({isToggleOn: this.state.isToggleOn ? 
    false : true});
}

1)除了代码风格之外,这些有什么区别吗? 所有方法似乎都适合我,我找不到任何区别(除了可读性)。

2)我想,this.setState只是“setter”,如何将“prevState”传递到该函数中?

3)这样写代码(第3种方法)是不是错误?我从“老派”变成了5年多没有开发,现在又回到了慢慢开发。第一个示例对我来说很难理解(因为箭头函数和匿名函数),第二个示例更清晰一些,但最后一个示例对我来说是最不言自明的。


现实生活中的例子

“真正的学习(生活)”是我现在正在努力的例子: 在我学习的过程中,我正在尝试编写自己的计算器(仅从基本功能开始)。由于糟糕的“设计”(我发现使用一些数组、字段、列表而不是仅“变量A,变量B”会更好,但无论如何都不会少......)。 我的应用程序结构是:

  • 计算器
    • 结果标题
      • 输入(结果)
      • 输入(用于打印方程)
    • 计算按钮 (0)
      • 按钮
    • ...
    • 计算按钮 (X)
      • 按钮

CalcButton 包含其值的属性([0...9]、x、/、+、-、C、...)和事件处理程序(numberClick、operatorClick)。当按下数字按钮时,它会将其状态提升到计算器,根据“isFirst”的状态,将数字添加到 valueA 或 valueB。 operatorClick 包含其自身功能的开关,如果按下 x、/、+、-,则会将 isFirst 设置为 false,并且用户可以继续使用第二个数字 (valueB)。现在这个处理程序的代码:

onNumberClick(e) {
    function appendA() {
        return {valueA: this.state.valueA + e};
    }

    function appendB() {
        return {valueB: this.state.valueB + e};
    }

    this.setState(this.state.isFirst ? appendA : appendB);

    /*
    if(this.state.isFirst) { 
        this.setState({valueA: this.state.valueA + e});
    } else {
        this.setState({valueB: this.state.valueB + e});
    }
    */
}

带注释的代码与第三个示例基本相同,甚至是未注释的变体,只是有一些“可读性”改进。最近 2 天,如果有可能使用一些匿名箭头函数,我就陷入困境,所以我不需要重复代码(一次用于 valueA,一次用于 valueB)。由于javascript及其缺乏对象引用,我能想到的唯一解决方案是通过字符串传递参数(“valueA”||“valueB”),但我认为这不是一个好的解决方案。这里重要的是(如顶部的示例所示),新的状态值是从其先前的值派生(这就是为什么我仍在考虑使用箭头匿名函数)。

有人可以向我展示一些如何实现这一目标的示例吗?这里是否需要箭头函数(是否可以通过箭头函数来做到这一点?)或者这个“代码”很好,但我发现没有问题?

最佳答案

React 批量状态更新。如果在代码的一个部分中使用 setState 更新状态,然后代码的其他部分同步再次调用 setState,则先前的状态值集可能还没有反射(reflect)在 this.state 中。例如:

class App extends React.Component {
  state = {};
  componentDidMount() {
    this.setState({ foo: 'foo' });
    console.log('after setting state, this.state.foo is:', this.state.foo);
    // so, further logic that depends on this.state.foo being 'foo' will fail
  }
  render() {
    return 'My App';
  }
}

ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>

换句话说,你无法可靠地做到

this.setState({ someProp: someVal });
// refer to this.state.someProp here
// because it may well refer to the state before it was updated
// not the new state which contains someVal

如果像您的特定情况一样,您没有多个同步状态更新 - 那么就没有问题,因为状态几乎会在单击后立即更新,然后再处理另一次单击。所以,你的

handleClick() {
  this.setState({isToggleOn: this.state.isToggleOn ? 
    false : true});
}

是安全的 - 或者,更简洁地说:

handleClick() {
  this.setState({isToggleOn: !this.state.isToggleOn });
}

只要您不在 handleClick 之前或之后立即执行依赖于或更改 this.state.isToggleOn 的操作即可。

您只需要功能版本,例如

handleClick() {     
    this.setState(function (prevState){
      return {isToggleOn: !prevState.isToggleOn}
    });
}

如果在重新渲染之前状态可能刚刚由上面的代码设置(同步)。请参阅此答案中的第一个片段作为示例 - 在这种情况下,如果您想再次调用 this.setState,并使用 this.state.foo 的值这是刚刚设置的,您需要使用回调表单。

I thought, this.setState is only "setter", how the "prevState" can be passed into that function?

当调用 setState 时,React 内部会跟踪状态的当前值,并将更新后的值传递到回调中,尽管组件的 this.state 可能尚未更新。

Is it mistake to write the code like this (3th approach)?

一点也不,只要您意识到限制即可。 (如果您的 setState 不依赖于之前刚刚通过调用 this.setState 设置的状态值,那么您的第三种方法就是很好。)

仅举一个人为的示例,如果您的应用程序有一个增加计数器的按钮,以及另一个按计数器数量增加状态值的按钮,则一种选择是将回调版本与多次调用结合使用设置状态:

updateSum() {
  for (let i = 0; i < this.state.count; i++) {
    this.incrementByOne();
  }
}
incrementByOne() {
  this.setState(prev => ({ sum: prev.sum + 1 }));
}

上面的 incrementByOne 由于被多次调用,因此仅在使用回调版本时才有效。如果是的话

this.setState({ sum: this.state.sum + 1 });

它将无法正常工作,因为 this.state.sum 不会从之前对 incrementByOne 的同步调用中更新。

关于javascript - "Good"如何在 React 中更新状态(从之前的值),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69081468/

相关文章:

javascript - Websockets 和二进制数据

javascript - 监视在被拒绝的 promise 中调用的函数

php - 不能使用带有返回 void 类型提示的箭头函数

javascript - rails : Change form submit image on hover using image_submit_tag

javascript - 快速获取 keyup/keydown 事件值的方法

javascript - 关于 Vue 模板中的更改未被解雇

javascript - 导出提供者函数和附着对象

javascript - React : Passing data between components using Router in App. js(父组件)

javascript - 语法错误 : invalid arrow-function arguments (parentheses around the arrow-function may help)

javascript - 尝试理解此字符串插值中的 `${c}` 如何指向数组中的元素