如何解决“无法在已卸载的组件上执行React状态更新”。 React Native中的错误

时间:2019-05-18 23:07:49

标签: javascript android react-native

我正在获取本地数据库(sqlite)中的数据并更新状态,并且出现此错误:

  

无法在已卸载的组件上执行React状态更新。这是> no-op,但表示您的应用程序中发生内存泄漏。要进行修复,请> componentWillUnmount方法取消所有预订和异步任务。

没有办法帮助我。


_isMounted = false;
  constructor(props) {
    super(props);
    this.state = {
      slug: "",
      value: "",
      cod_year: "",
      months: [],
      years: [],
      loadingData: true,
    };
  }
  db = openDatabase({ name: 'test.db', createFromLocation : '~my_finances.db'});

  getYears = () => {
    if(this.state.loadingData){
      this.db.transaction((txn)=>{
        txn.executeSql(
            "SELECT cod, slug FROM year",
            [],
            (tx, res) => {
                if(res.rows.length > 0){
                    rows = [];
                    for(let i=0; i<res.rows.length;i++){
                        rows.push(res.rows.item(i));
                    }
                    this.setState({years: rows}, {loadingData: false});
                }
            }
        )
      })
    }

  }

  componentDidMount(){
    this._isMounted = true;
    this.getYears();
  }

  render() {
    const state = this.state;
    if(!state.loadingData){
      const pickerItens = state.years.map((record, index) => {
        <Picker.Item label={record.slug} value={record.cod}/>  
      })
      return (
        <View style={{flex: 1}} >
          <ScrollView style={styles.container}>
            <View style={styles.form_add}>
              <Text style={styles.form_slug} > Adicionar </Text>
              <TextInput 
                  placeholder="Digite o mês..."
                  onChangeText={(slug) => { this.setState({slug}) }}
                  value={this.state.slug}
                  style={styles.input_add}
              />
              <TextInput 
                  placeholder="Digite o valor..."
                  onChangeText={(value) => { this.setState({value}) }}
                  value={this.state.value}
                  style={styles.input_add}
              />
              <Picker onValueChange = {(cod_year) => {this.setState({cod_year})}}>
                { pickerItens }
              </Picker>

              <Button color="#7159C1" title="Salvar" onPress={() => this.addYear()} /> 
            </View>
          </ScrollView>
          <Footer navigate={this.props.navigation.navigate} />
        </View>
      );
    }else{
      <Text> Loading... </Text>
    }
  }

2 个答案:

答案 0 :(得分:1)

无论何时有任何任务在运行,您都可以通过向后导航来拉开屏幕,

此警告出现

您无需担心任何事情。

这是正常警告。

假设您已完成setState的运行,请卸载所有内容。 因此,这里的系统会认为我正在做setState,但是我没有类,这个或/和变量来做。

因此,它只是警告您所有内容均已卸载,而我无法在已卸载的组件上进行操作。

关于杀死异步任务...,

假设您将计时器设置为1分钟,并且您每对{1}进行一次on状态变量设置。

setState

现在无论您做什么,这1分钟计时器将无限运行直到您终止应用程序。

因此,系统建议您在卸载组件时取消此类任务。

let this.timerState = setTimeout(() => { this.setState({ timer: this.state.timer + 1 }); }, 1000); 的生命周期方法clearTimeout(this.timerState)也是如此。

所以不要打扰警告没有泄漏的东西。

答案 1 :(得分:0)

在构造函数中初始化db并将其添加到状态,如下所示:

constructor(props: Props) {
  super(props);

 const db = SQLite.openDatabase({
      name: 'test.db',
      location: 'default',
      createFromLocation: '~my_finances.db',
    },
    () => {},
    error => {
      console.log(error);
    }
  );

  this.state = {
      db,
      slug: "",
      value: "",
      cod_year: "",
      months: [],
      years: [],
      loadingData: true,
  };
}

然后在componentDidMount上获取getYears,如下所示:

getYears = () => {
   const { loadinData, db } = this.state
   if(loadingData){
      db.transaction((txn) => {
        txn.executeSql(
           "SELECT cod, slug FROM year",
           [],
           (tx, res) => {
               if(res.rows.length > 0){
                    let rows = [];
                    for(let i=0; i<res.rows.length;i++){
                        rows.push(res.rows.item(i));
                    }
                    this.setState({years: rows, loadingData: false});
               }
           })
       })
    }
 }

componentDidMount() {
   this.getYears();
}

只需按以下步骤关闭componentWillUnMount上的连接即可:

componentWillUnmount() {
    const { db } = this.state;
    db.close();
}

希望对您有帮助。