0

I'm building my first React Native app with react navigation (coming from a web react background).

Normally, I just useState for much of what I handle. For example, rendering a list of components based on the number of objects returned by a database query (Friend List type feature) or for a multi-step user sign up (each page adds some information to the state, and the last one sends all the information in a post request).

However, it seems I can't do that with react native ? I'm using React navigation, so every screen component I make is wrapped inside a <Stack.Screen> component. How can I pass props so that I can update the state of parent components ? Do i necessarily need redux for this ?

Here's a description of how i previously did this in React. The feature is a 5 stage sign up process.

The user navigates to the signup page, components for url/page1 load. They input their name and email and hit next. The button updates the app.state using the setState prop it received from it's parent. It then navigates to url/page2.

url/page2 components have the user input their address. The user hits next, the button updates the state and navigates to the next one. Etc.

Each new page adds new information to the state until the final "submit" button takes all this information and submits it via a POST request to the backend.

In react native, my app.js is organized like this:

<NavigationContainer>
        <Stack.Navigator initialRouteName = "TempHome">
          <Stack.Screen name="TempHome" component={TempHome} />
          <Stack.Screen name="Welcome" component={Welcome} />
          <Stack.Screen name="LogIn" component={LogIn} />
          <Stack.Screen name="SignUp" component={SignUp} />
          <Stack.Screen name="ProfileSetupA" component={ProfileSetupA} />
          <Stack.Screen name="ProfileSetupB" component={ProfileSetupB} />
          <Stack.Screen name="ProfileSetupC" component={ProfileSetupC} />
          <Stack.Screen name="ProfileSetupD" component={ProfileSetupD} />
          <Stack.Screen name="ProfileSetupE" component={ProfileSetupE} />
          <Stack.Screen name="ProfileSetupF" component={ProfileSetupF} />
          <Stack.Screen name="ProfileSetupG" component={ProfileSetupG}/>
          <Stack.Screen name="ProfileSetupH" component={ProfileSetupH}/>
          <Stack.Screen name="PetProfileHome" component={PetProfileHome} />
          <Stack.Screen name="PetProfileScheduledActivities" component={PetProfileScheduledActivities} />
          <Stack.Screen name="PetProfileAccount" component={PetProfileAccount} />
          <Stack.Screen name="PetProfileTraits" component={PetProfileTraits} />
          <Stack.Screen name="PetProfileInvitation" component={PetProfileInvitation} />


          <Stack.Screen name="Notification" component={Notification} />
          <Stack.Screen name="NetworkExample" component={Network} />
          <Stack.Screen name="MapExample" component={MapExample} />
          <Stack.Screen name="ShareExample" component={ShareExample} />

        </Stack.Navigator>
</NavigationContainer>

Each of these screens navigates to the next one in the list using const ProfileSetupF = () => navigation.navigate('ProfileSetupF')

How can use my state props as previously in this context ? I don't want all my setup screens to be in the same component or stack.Screen because I want the user to be able to use the back button and the nice animations that come with pushing a new screen to the stack. I've been told I should use Redux for this. Any advice ?

4
  • You need to use React Context API reactjs.org/docs/context.html or a state management library like redux or mobx Commented Jul 5, 2021 at 14:27
  • you need react context and maybe combine it with reducer. Or maybe just go with redux. Or maybe you just have to pass params with each time you navigate, such navigation.navigate('ProfileSetupF', { myPrevState: 'anything' }) Commented Jul 5, 2021 at 14:45
  • then you can access myPrevState in your next screen. const { myPrevState } = route.params. You can access route with props, or use the hooks useRoute. passing params reactnavigation.org/docs/params , route hooks reactnavigation.org/docs/use-route Commented Jul 5, 2021 at 14:48
  • Passing parameters with navigation doesn't work, because the params need to be JSON-serializable, which means no function. So i can pass the state, but I can't pass the setState function which would allow me to update the state with user input. Redux is looking like my best option, but for both Redux and Context, I always thought it was for data that is considered "global" to my entire app (like settings), not the state data for a specific route. Commented Jul 5, 2021 at 15:17

1 Answer 1

0

The more common way to manage this use case is with context API: https://reactjs.org/docs/context.html

There is no need to make this context global, you can wrap for example only the authentication components with the context provider.

Ideally you will have an AuthenticationContext like this:

const AuthContext = createContext();
  
export const AuthProvider = (props) => {
    const [user, setUser] = useState(null);
    
    const login = async () => {
        // LOGIN FUNCTIONS
        login().then(userDocument => setUser(userDocument))
    }


    return (
        <AuthContext.Provider
            value={{
                user,
                login: login
            }}
        >
            {props.children}
        </AuthContext.Provider>
    );
};

then you will wrap your NavigationProvider with the AuthProvider e you will find if there is a user logged in with:

const {user} = useContext(AuthContext)

A more better approach is to build a dynamic navigator based on the AuthContext, for example:

const AppNavigator = () = {
  const {user} = useContext(AuthContext);

  return (
<>
        {!user ? <Stack.Navigator initialRouteName = "Auth">
          <Stack.Screen name="TempHome" component={TempHome} />
          <Stack.Screen name="Welcome" component={Welcome} />
          <Stack.Screen name="LogIn" component={LogIn} />
          <Stack.Screen name="SignUp" component={SignUp} />
        </Stack.Navigator>
       :
       <Stack.Navigator initialRouteName = "TemHome">
          <Stack.Screen name="ProfileSetupA" component={ProfileSetupA} />
          <Stack.Screen name="ProfileSetupB" component={ProfileSetupB} />
          <Stack.Screen name="ProfileSetupC" component={ProfileSetupC} />
          <Stack.Screen name="ProfileSetupD" component={ProfileSetupD} />
          <Stack.Screen name="ProfileSetupE" component={ProfileSetupE} />
          <Stack.Screen name="ProfileSetupF" component={ProfileSetupF} />
          <Stack.Screen name="ProfileSetupG" component={ProfileSetupG}/>
          <Stack.Screen name="ProfileSetupH" component={ProfileSetupH}/>
          <Stack.Screen name="PetProfileHome" component={PetProfileHome} />
          <Stack.Screen name="PetProfileScheduledActivities" component={PetProfileScheduledActivities} />
          <Stack.Screen name="PetProfileAccount" component={PetProfileAccount} />
          <Stack.Screen name="PetProfileTraits" component={PetProfileTraits} />
          <Stack.Screen name="PetProfileInvitation" component={PetProfileInvitation} />


          <Stack.Screen name="Notification" component={Notification} />
          <Stack.Screen name="NetworkExample" component={Network} />
          <Stack.Screen name="MapExample" component={MapExample} />
          <Stack.Screen name="ShareExample" component={ShareExample} />

        </Stack.Navigator>
</>
  )
}

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.