优雅的 ES6 方式在 React 中更新状态

Posted

技术标签:

【中文标题】优雅的 ES6 方式在 React 中更新状态【英文标题】:Elegant ES6 way to update state in React 【发布时间】:2017-11-12 15:30:37 【问题描述】:

在 React 中更新 state 的语法发生了很大变化。我正在尝试找到最简单、最优雅的方式来启动和更新它。

得到这个 RN 代码:

const  quotes  = require('./quotes.json')

class QuoteScreen extends Component 
  state = 
    QuoteIndex: 0
  
  render() 
    return (
      <Image ...>
        <View ...>
          ...
          <ButtonNextQuote
            onPress=() => 
              this.setState((prevState, props) => 
                return 
                  QuoteIndex: (prevState.QuoteIndex + 1) % (quotes.length - 1)
                
              )
            
          />
        </View>
      </Image>
    )
  

是否可以减少stateonPress中的更新?

希望避免调用匿名函数两次,但又不想引用和绑定处理程序。还想避免使用return..

【问题讨论】:

【参考方案1】:

我会将更新函数存储在类外的变量中,例如

const newState = (QuoteIndex: i) => (QuoteIndex: (i + 1) % nQuotes);

(当然你可以选择以任何你喜欢的方式定义函数,如果不内联,也许“简洁”对你来说不再那么重要了)

然后你就可以拨打this.setState(newState):

onPress=() => this.setState(newState)

【讨论】:

【参考方案2】:

我会这样做。我在 setState 的回调 (prevState) 的第一个参数中使用了object destructuring,并且出于性能原因,我使用了单独的函数而不是匿名函数。另外请注意,我不需要手动将函数绑定到this,因为我已经为它使用了箭头函数。

const  quotes  = require('./quotes.json')

class QuoteScreen extends Component 
  state = 
    QuoteIndex: 0
  

  handleUpdateState = () => 
    this.setState(( QuoteIndex ) => (
      QuoteIndex: (QuoteIndex + 1) % (quotes.length - 1)
    ));
  

  render() 
    return (
      <Image ...>
        <View ...>
          ...
          <ButtonNextQuote
            onPress=this.handleUpdateState
          />
        </View>
      </Image>
    )
  

【讨论】:

由于这个问题是用 ES6 标记的​​,因此可能值得指出您正在使用实验性功能(公共类字段)并简要说明启用它们需要做什么。 对不起,我的错。基本上你有这个开箱即用的功能,最新版本的 babel 集成到 create-react-app 和 react-native 的依赖列表中。这是E6+,谢谢指出【参考方案3】:

我认为一个流行的好方法是

    通过向 this.setState 提供回调来使用“功能性 setState”,以避免批量状态更新中出现一些奇怪的情况

    “将状态变化与组件类分开声明”,以便获得新状态的函数可以单独重用和测试。

查看this article,了解 Dan Abramov 的推文对这种方法的详细解释

例子:

const  quotes  = require('./quotes.json')

// keep pure function outside component to be reusable, testable
const getQuoteIndex = ( QuoteIndex ) => (
  QuoteIndex: (QuoteIndex + 1) % (quotes.length - 1)
)

class QuoteScreen extends Component 
  state = 
    QuoteIndex: 0
  
  // arrow function will take care of this binding
  handlePress = () =>  this.setState(getQuoteIndex) 
  render() 
    return (
      <Image ...>
        <View ...>
          ...
          <ButtonNextQuote
            onPress=this.handlePress
          />
        </View>
      </Image>
    )
  

【讨论】:

【参考方案4】:

正如其他人所说,您希望避免每次运行 render 时都重新定义事件处理程序。我更喜欢将对象传递给setState 而不是回调函数:

_handlePress = () => 
  this.setState(
    QuoteIndex: (this.state.QuoteIndex + 1) % (quotes.length - 1)
  );
;

onPress=this._handlePress

这更容易阅读,因为它明确了状态的来源。此外,您不必跟踪额外的回调函数。

【讨论】:

以上是关于优雅的 ES6 方式在 React 中更新状态的主要内容,如果未能解决你的问题,请参考以下文章

React 状态未更新,尝试使用 ES6 语法

我想以不可变的方式更新状态对象,以便react和redux正常工作?

react创建组件的几种方式及其区别

03react 之创建component

react创建组件的三种方式

ES6/React:为啥我的三重嵌套 setState 更新不起作用?