Bhavan Patel
Bhavan Patel

Reputation: 1755

React-native: rendering view before fetching data from Storage

I am trying to render Signin component if user not logged in and if user logged in I am trying to render Home component. On Signin component set Storage 'isLIn' to 'true' On Signout [from home component] set Storage 'isLIn' to 'false' and Every time React-Native App opens checking Storage and Setting State as value of Storage.

Please look at code:

import React, { Component } from 'react';
import { AsyncStorage } from 'react-native';
import { Scene, Router } from 'react-native-router-flux';
import Login from './login_component';
import Home from './home_component';

var KEY = 'isLIn';

export default class main extends Component {
  state = {
    isLoggedIn: false
  };

  componentWillMount() {
    this._loadInitialState().done();
  }

  _loadInitialState = async () => {
    try {
        let value = await AsyncStorage.getItem(KEY);
        if (value !== null && value === 'true') {
          this.setState({ isLoggedIn: true });
        } else {
          this.setState({ isLoggedIn: false });
        }
    } catch (error) {
      console.error('Error:AsyncStorage:', error.message);
    }
  };

  render() {
    const _isIn = (this.state.isLoggedIn===true) ? true : false;
    return (
        <Router>
          <Scene key="root" hideNavBar hideTabBar>
            <Scene key="Signin" component={Login} title="Signin" initial={!_isIn} />
            <Scene key="Home" component={Home} title="Home" initial={_isIn}/>
          </Scene>
        </Router>
    );
  }
}

I don't know why but view render first before Storage gets value. According to lifecycle of react-native render() execute only after componentWillMount() as React_Doc says.

I am using AsyncStorage to get set and remove Storage and also using React-Native-Router-Flux for routing.

I have tried solutions:

Upvotes: 2

Views: 2179

Answers (2)

Murat Karag&#246;z
Murat Karag&#246;z

Reputation: 37594

Since what you are doing is asynchronous you can not tell the lifecycle to wait for it. But React provides states and these you can use e.g.

state = {
    isLoggedIn: false
    isLoading: true
  };

And set the state in the async

_loadInitialState = async () => {
    try {
        let value = await AsyncStorage.getItem(KEY);
        if (value !== null && value === 'true') {
          this.setState({ isLoggedIn: true, isLoading: false });
        } else {
          this.setState({ isLoggedIn: false, isLoading: false });
        }
    } catch (error) {
      console.error('Error:AsyncStorage:', error.message);
    }
  };

And then in your render method you can place a placeholder until your asynctask is finished

render() {
 if(this.state.isLoading) return <div> Loading... </div>
 else return...
}

Upvotes: 2

Hadas Zeilberger
Hadas Zeilberger

Reputation: 761

Invoking setState in componentWillMount does NOT trigger a re-rendering. componentWillMount runs after state has been set and before the view has been re-rendered. From React Native Docs:

"componentWillMount() is invoked immediately before mounting occurs. It is called before render(), therefore setting state in this method will not trigger a re-rendering. Avoid introducing any side-effects or subscriptions in this method." - https://facebook.github.io/react/docs/react-component.html#componentwillmount

Instead, you should call _loadInitialState in componentWillReceiveProps()

Upvotes: 0

Related Questions