Search code examples
androidreact-nativemobileasyncstorage

react native keep re-render the view every 10 ms when using AsyncStorage


I am newbie in ReactNative. ( I am very familiar with Raw Android)

Yesterday when I was using AsyncStorage ( incorrectly I think) , I met a problem that the View kept re-rendering every n millionseconds.

my code:

import React,  { Component} from 'react';
import {Image, Platform, StyleSheet, Text, View, Button} from 'react-native'
import { AsyncStorage } from "react-native"

export default class StorageDemo extends Component{

  constructor(props){
    super(props)
    AsyncStorage.setItem("visitTimes", 100)
    this.state = {
      isLoaded: false,
      visitTimes: 0
    }
  }

  readData = async () => {
    try{
      const result = await AsyncStorage.getItem("visitTimes")
      this.setState(
        {
          visitTimes: result,
          isLoaded: true
        }
      )
      console.info("== loaded, this.state: ")
    }catch(error){
      console.error(error)
    }
  }

  render() {
    this.readData()

    if(this.state.isLoaded){
      return(
        <View>
          <Text>Loaded!  </Text>
        </View>
      )
    }else{
      return(
        <View>
          <Text>Loading... </Text>
        </View>
      )
    }

  }
}

Also I opened a logcat window to check the log, I was shocked by the log: it kept re-rendering the View every 10 ms.

enter image description here

My environment:

  • Android SDK: 27
  • Windows
  • ReactNative 0.55
  • Device: VIVO Y67A ( Android 6.0 , 4G RAM)

code could be found here: https://github.com/sg552/react_native_lesson_demo/blob/master/screens/StorageDemo.js

I know my code is not correct (using async, await) , so my question is:

How to read from AsyncStorage and render it to page? How to correct my code?

thanks a lot!


Solution

  • Okay, so the problem is that you are calling your func this.readData() inside the render, and that function itself is calling setState which whenever is called, changes the state, which triggers a re-render on the component. So in this situation you have caused an infinite loop in the code, because setState calls render, which in turn calls setState again and you run out of memory.

    To fix this quickly, you can remove the function call from your render, and add it to a button, so its only called when you want it to. Something like this:

    import React,  { Component} from 'react';
    import {Image, Platform, StyleSheet, Text, View, Button} from 'react-native'
    import { AsyncStorage } from "react-native"
    
    export default class StorageDemo extends Component{
    
      constructor(props){
        super(props)
        this.state = {
          isLoaded: false,
          visitTimes: 0
        }
      }
    
      readData = async () => {
        try{
          const result = await AsyncStorage.getItem("visitTimes")
          this.setState(
            {
              visitTimes: result,
              isLoaded: true
            }
          )
          console.info("== loaded, this.state: ")
        }catch(error){
          console.error(error)
        }
      }
    
      render() {
    
        if(this.state.isLoaded){
          return(
            <View>
              <Text>Loaded! {this.state.visitTimes} </Text>
              <Button 
               onPress={() =>  {
                AsyncStorage.setItem("visitTimes", "100")
                this.setState({isLoaded: false})
                }} 
               title="Set Storage Item"
               />
            </View>
          )
        }else{
          return(
            <View>
              <Button 
              onPress={this.readData}
              title="Load from async storage"></Button>
            </View>
          )
        }
    
      }
    }
    

    Try this and this should give you the value from localStorage!