react-native 之"Cannot update during an exitsting state transition" 与 函数方法bind()/箭头函数有关?

react-native Warning:setState(...):Cannot update during an exitsting state transition...
这个问题出现的确实让我措手不及,结果是这样的

业务逻辑:在页面HomePage中点击setting-item按钮弹出页面ThemePage,并选择自己喜欢的样式进行样式的切换。
导致错误操作:点击了js页面一个方法onPress={this.onSelectThemeItem(key)}所导致的。即第14行代码中的方法onPress 的开始触发了问题!

代码是这样的,下面的代码是会出现上面错误代码

extends Component组件的js页面中的部分代码展示

export default class xxComponent extends Component {

   ...
   ..

   onSelectThemeItem(key) {
       this.props.onModalClose();
       this.themeDao.saveTheme(ThemeFlags[key]);
       //发送通知通知修改主题
       deviceeventemitter.emit('ACTION_BASE',ACTION_NOTIFY.changeTheme,ThemeFactory.createTheme(ThemeFlags[key]))
   }

   getThemeItem(key) {
       let themeTitle = <TouchableOpacity style={{flex: 1}} onPress={this.onSelectThemeItem(key)}>
           <View style={[{backgroundColor: ThemeFlags[key]},styles.themeItem]}>
               <Text style={{color: 'white',fontWeight: '300'}}>{key}</Text>
           </View>
       </TouchableOpacity>;

       return themeTitle;
   }

    ...
    ..
}

而这里出现的问题:view绘制中,再次更改props,导致view会再次去render,报错!就在14行的代码..

这种问题最可能出现的位置,就是在你所触发的方法中需要创建一个匿名函数(箭头函数),而你确没能满足。
为什么?下文解决

解决问题方法
代码

换作

分析”Cannot update during an exitsting state transition” 与 函数方法bind()箭头函数的关系

从上面犯错的代码截取一段代码来看,逻辑是在一个页面中通过点击页面中的一个组件而触发一个事件。
从这行代码上看,事实确是在刚执行到该页面js代码,进行渲染的时候就会去执行花括号中的方法this.onSelectThemeItem(key) ,导致在view渲染中又请求渲染的操作。从而报以上的错误

首先了解下平时我们写bind()方法箭头函数的几种形式
第一种

...
xxFunction(){..}
...
<XXView xxxx={this.xxFunction.bind(this)} />

第二种

constructor(props) {
    super(props);
    this.xxFunction= this.xxFunction.bind(this);
}

...
xxFunction(){..}
...

第三种

...
xxFunction= ()=>{..};
...
<XXView xxxx={this.xxFunction} />

第四种

...
xxFunction(){..}
...
<XXView xxxx={()=>this.xxFunction()} />

bind函数箭头函数区别:
在ES5下,React.createClass会把所有的方法都bind一遍,这样可以提交到任意的地方作为回调函数,而this不会变化。
在ES6下,你需要通过bind来绑定this引用,或者使用箭头函数(它会绑定当前scope的this引用)来调用

由此能够得出=>>>bind()方法箭头函数在使用是等价的。且在其形式上2和3是一致的、1和4是一致的。

通过 bind() 函数会创建一个函数(称为绑定函数),该新函数是由指定的this值和初始化参数改造的原函数拷贝。

好的,让我们一同看下代码

/** * Created by YJH on 2018/6/13. */
import React,{Component} from 'react';
import {
    BackAndroid,} from 'react-native';

export default class Backforward{
    constructor(props){
        this.backpress = this.onHardwareBackforward.bind(this);
        this.props=props;//由于不是component组件,所以后面使用props时候,需要将props通过this.props存储起来
    }

    componentDidMount(){
        if(this.props.backforward){
            BackAndroid.addEventListener("backforward",this.backpress);
        }
    }

    componentwillUnmount(){
        if(this.props.backforward){
            BackAndroid.removeEventListener("backforward",this.backpress);
        }
    }
    onHardwareBackforward(e){

        return this.props.backforward(e);
    }

}

通过bind绑定函数onHardwareBackforward返回一个原始函数拷贝的新函数this.backpress;并在17行和23行代码上使用react-native内的组件BackAndroid添加了安卓手机返回按钮的监听,和移除监听。当用户点击手机返回按钮则触发26行代码onHardwareBackforward方法执行,并调用暴露在js页面中的方法执行关闭当前的js页面

就是下面代码

export default class xxDetailPage extends Component {

    constructor(props) {
        super(props);
        //实现对android手机返回按钮的监听返回功能
        this.backforward = new Backforward({backforward: (e) => this.onBackforward(e)}); ... } componentDidMount(){ this.backforward.componentDidMount(); } componentwillUnmount(){ this.backforward.componentwillUnmount(); } onBackforward(e) { this.goBack(); return true; } goBack() { if (this.state.isBack) { this.webView.goBack(); } else { this.props.navigator.pop(); } } ... .. }

Backforward.js第28行代码调用xxDetailPage.js第16行代码,完成了回调监听!当然,这种方式使用箭头函数也是可以实现的!

参考内容
https://blog.csdn.net/sinat
https://developer.mozilla.org
http://bbs.reactnative.cn

相关文章

一、前言 在组件方面react和Vue一样的,核心思想玩的就是组件...
前言: 前段时间学习完react后,刚好就接到公司一个react项目...
前言: 最近收到组长通知我们项目组后面新开的项目准备统一技...
react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom...