0

I'm making a small app in react native, it's a basic login workflow that use a couple of screen (login and home), that are shown based on user state; in App.js i have a bunch of state that im using to enable/disbale views, buttons, show username and so on. I have both the login screen and the home screen in external components. i'm wonder (besides using context) if there is a way to have these states (and functions) available to child screen

this is part of my code:

App.js

export default function App() {
  const [isLoading, setIsLoading] = useState(true);
  const [isLogged, setIsLogged] = useState(false);
  const [userToken, setUserToken] = useState(null);
  const [userProfile, setUserProfile] = useState(null);
  const [email, setEmail] = useState(null);
  const [password, setPassword] = useState(null);
  const [loggingIn, setloggingIn] = useState(false);
  const [error, setError] = useState(null);

  const AppStack = createStackNavigator();

  useEffect(() => {
    AsyncStorage.getItem('userProfile').then((value) => {
      if (value) {
        console.log(JSON.parse(value)),
          setUserProfile(JSON.parse(value)),
          setIsLoading(false),
          setIsLogged(true);
      } else {
        setIsLoading(false), setIsLogged(false);
      }
    });
  }, []);

  const doLogout = async () => {
---- LOGOUT CODE 
}
const doLogin = async () => {
----- LOGIN CODE and UPDATE of state and asyncstorage
}
return (
    <NavigationContainer>
      <AppStack.Navigator initialRouteName="Login">
        <AppStack.Screen name="Login" component={Login} />
        <AppStack.Screen
          name="Home"
          component={Home}
          options={{ headerShown: false }}
        />
      </AppStack.Navigator>
    </NavigationContainer>
  );

Login.js

const Login = ({ loggingIn, userProfile }) => {
  console.log(userProfile);
  return (
    <View style={styles.container}>
      <Button
        title="Login to Site"
        onPress={() => doLogin()}
        disabled={loggingIn}
      >
        {userProfile && userProfile.name} Login to Site
      </Button>
    </View>
  );
};

how can access loggingIn (or even userProfile) and doLogin() function that i set and create (and update) in App.js? there should be an easy way (beside useContext) for simple uses like this one.

popeating
  • 386
  • 1
  • 2
  • 16

1 Answers1

0

You can pass parameters to routes. See the first section here:

https://reactnavigation.org/docs/params/

But you may instead want to move the states to their relevant screen component or other react component. Then, in the parent component, pass the values to the child component. See TestComponent.js below. Then, in the child component, we can use the props that we passed in from the parent component. See TestChildComponent.js below.

I have also provided App.js, TestNavigator.js, and TestScreen.js, so that you can just copy/paste them and test yourself.

Also, if you find yourself managing too many states with the useState hook, then you can look into using Redux for state management instead of the useState hook.


Code below:


TestComponent.js:

import React, {useState} from "react";
import {View, StyleSheet} from "react-native";
import ChildComponent from "./TestChildComponent";

const TestComponent = props => {
    const [value, setValue] = useState("Bilbo");

    return (
        <View style={styles.container}>
            <ChildComponent value={value} setValue={setValue} />
        </View>
    );
};



const styles = StyleSheet.create({
    container: {
        flex: 1,
        margin: 100,
    },
});

export default TestComponent;

TestChildComponent.js:

import React from "react";
import {StyleSheet, Text, Button, View} from "react-native";

const ChildComponent = props => {

    const buttonPressHandler = () => {
        props.setValue("Frodo");
    };

    return (
        <View style={styles.child}>
            <Text>Press Me:</Text>
            <Button title={props.value} onPress={buttonPressHandler} />
        </View>
    );
};

export default ChildComponent;

const styles = StyleSheet.create({
    child: {
        flexDirection: "row",
        marginHorizontal: 25,
        justifyContent: "center",
        alignItems: "center",
    },
});

TestNavigator.js:

import React from "react";
import {createStackNavigator} from "@react-navigation/stack";

import TestScreen from "./TestScreen";

const TestStackNavigator = createStackNavigator();

export const TestNavigator = () => {

    return (
        <TestStackNavigator.Navigator>
            <TestStackNavigator.Screen name={"Test"} component={TestScreen}/>
        </TestStackNavigator.Navigator>
    );
};

App.js

import React from 'react';
import {StyleSheet, SafeAreaView} from 'react-native';
import {NavigationContainer} from "@react-navigation/native";

import {TestNavigator} from "./TestNavigator";

export default function App() {

    return (
        <NavigationContainer>
            <SafeAreaView style={styles.safeAreaView}>
                <TestNavigator />
            </SafeAreaView>
        </NavigationContainer>
    );
}

const styles = StyleSheet.create({
    safeAreaView: {
        flex: 1,
    }
});

TestScreen.js

import React from "react";
import TestComponent from "./TestComponent";

const TestScreen = props => {

    return (
        <TestComponent />
    );
};

export default TestScreen;
MoreFoam
  • 624
  • 1
  • 6
  • 25
  • thank you, your solution of course should work, but to build a 3 files app (app.js login.js home.js) with this solution i would nest 5 files! at this point i can use context, and keep a 3 files structure, adding the state and the functions in a context and inside the child grabbing what i need from the context – popeating Nov 25 '20 at 18:12
  • No problem, why can't you have more than 3 files? Also, you can check out this link: https://reactnavigation.org/docs/params/. The first section will show you how to pass parameters to routes. – MoreFoam Nov 25 '20 at 18:16
  • well, it's not exaclty that i dont want more than 3 files, im just prototyping a piece for a lesson, and i wantted to stay on topic (login using an api), if i start to move things around (context, redux) it would become too diffuse, anyway i solved with a context, with the small footprint as possible – popeating Nov 25 '20 at 19:22