irondsd
irondsd

Reputation: 1240

Changing state in React native App.js from another component

I'm making authentication in an app, and I'm kind of stuck. I have 2 different navigations. One shows if the user is logged in and another one if not. Basically, a Sign in screen. It's working fine if I change the value manually upon the start. But I can't find a way to change a state when a user signs in, for example. Even though the value in auth module changes, it doesn't update in App.js So how can I update the App.js's state from Sign in screen, for example?

import React, { Component } from 'react';
import { AppRegistry, Platform, StyleSheet, Text, View } from 'react-native';
import DrawerNavigator from './components/DrawerNavigator'
import SignedOutNavigator from './components/SignedOutNavigator'
import auth from './auth'

type Props = {};
export default class App extends Component<Props> {
  constructor(props) {
    super(props)
    this.state = {
      isLoggedIn: auth.isLoggedIn
    }
  }

  render() {
    return (
      (this.state.isLoggedIn) ? <DrawerNavigator /> : <SignedOutNavigator />
    );
  }
}

AppRegistry.registerComponent('App', () => App)

and my auth module, which is very simple import { AsyncStorage } from 'react-native'; // try to read from a local file let api_key let isLoggedIn = false

function save_user_settings(settings) {
    AsyncStorage.mergeItem('user', JSON.stringify(settings), () => {
        AsyncStorage.getItem('user', (err, result) => {
            isLoggedIn = result.isLoggedIn
            api_key = result.api_key
        });
        isLoggedIn = true
    });
}
module.exports.save_user_settings = save_user_settings
module.exports.api_key = api_key
module.exports.isLoggedIn = isLoggedIn

Upvotes: 2

Views: 3192

Answers (1)

William Park
William Park

Reputation: 1767

First off, there are loads of ways to approach this problem. Because of this I'm going to try explain to you why what you have now isn't working.

The reason this is happening is because when you assign auth.isLoggedIn to your isLoggedIn state, you are assigning the value once, kind of as a copy. It's not a reference that is stored.

In addition to this, remember, React state is generally only updated with setState(), and that is never being called here, so your state will not update.

The way I would approach this problem without bringing in elements like Redux, which is overkill for this problem by itself, is to look into building an authentication higher order component which handles all the authentication logic and wraps your entire application. From there you can control if you should render the children, or do a redirect.

Auth Component

componentDidMount() {
 this._saveUserSettings(settings);
}

_saveUserSettings(settings) {
    AsyncStorage.mergeItem('user', JSON.stringify(settings), () => {
        AsyncStorage.getItem('user', (err, result) => {
            isLoggedIn = result.isLoggedIn
            api_key = result.api_key
        });
        this.setState({isLoggedIn: true});
    });
}

render() {
 const { isLoggedIn } = this.state;
 return isLoggedIn ? this.props.children : null;
}

App.js

render() {
   <AuthComponent>
      //the rest of authenticated app goes here
   </AuthComponent>
}

Here's a really quick, incomplete example. But it should showcase to you how you may want to lay your authentication out. You'll also want to consider error handling and such, however.

Upvotes: 2

Related Questions