skip to Main Content

I’m creating a React Native app in which some actions like adding to favorites require the user to be logged in.

The problem

If a certain action needs authentication, the following flow is executed:

  1. User tab over the favorite button(Protected action)
  2. A modal(screen with presentation: "modal") is rendered to allow the user to enter their credentials
  3. If the user is successfully logged in, the modal is closed and the user is directed to the screen on which it was located(goBack() navigation action).
  4. THE PROBLEM: user needs to press again over the favorite button, the idea is, if the user is successfully logged in, the action (add to favorites) is executed immediately without the user having to perform the action again.

NOTE: I can have different protected actions on the same screen

Question

how can I request the user to log in to perform the action and have the action executed automatically after successful login?
execute the protected action only once, only when the user logs in successfully and the modal is closed, if the user is already authenticated the protected action should not be executed again.

Example flow

function FavoriteScreen({ navigation }) {
  const { isAuthenticated } = useAuth();

  if (isAuthenticated) {
      addFavorite(productId);
  } else {
    navigation.navigate("LoginScreen");
  }
}

Things I’ve tried

  1. Send a callback through the parameters(called nexAction) from the protected action screen to the login screen, run the callback after successfully log in, and close the modal, but I’m getting non-serializable warning, and this screen implements deep linking, so I cannot ignore the warning as the documentation suggests.
if (isAuthenticated) {
  addFavorite();
} else {
  navigation.navigate(NavigationScreens.LoginScreen, {
    nextAction: addFavorite,
  });
}
  1. Use the focus event to run the protected action after the user is successfully logged in and the modal is closed. This approach has some problems, each time user focuses on the screen and is authenticated, the protected action is going to be run, and there may be more than one protected action on the screen, meaning that they will all be executed when the screen is focused.
useEffect(() => {
  const unsubscribe = navigation.addListener('focus', () => {
    if (isAuthenticated) {
      addFavorite();
    }
  });

  return unsubscribe;
}, [isAuthenticated, navigation, addFavorite]);

2

Answers


  1. Have you tried an effect?

    // Will run once on mount and again when auth state changes
    useEffect(() => {
      if (isAuth) {
        // code runs when auth changes from false to true
      } else {
        // code runs when auth changes to false
      }
    }, [isAuth]);
    

    You can’t send a function on nav params, but you can send data. You can try parroting the data back from the login screen and performing your one time action like this:

    const Fav = ({ route }) => {
      const { isAuthenticated } = useAuth();
    
      const {nextAction} = route.params;
    
      useEffect(() => {
        if (isAuthenticated) {
          // If login navigated back to us with a nextAction, complete it now
          if (nextAction === CallbackActions.ADD_FAVORITE) addFavorite();
        } else {
          navigation.navigate(NavigationScreens.LoginScreen, {
            nextAction: CallbackActions.ADD_FAVORITE, // Send some data to the login screen
          });
        }
      }, []);
    };
    
    const Login = ({ route }) => {
      const {nextAction} = route.params;
    
      // Do login stuff
      login().then(() => {
          navigation.navigate(NavigationScreens.FavoriteScreen, {
            nextAction, // Send back the caller's nextAction
          });
      });
    };
    
    Login or Signup to reply.
  2. I think you’re on the right path with useEffect. What about storing the user action when clicking a protected action, and then performing the action and clearing the stored value after the user has logged in?

    Something like:

    const [pendingAction, setPendingAction] = useState();

    user clicks addFavorite action, but is not logged in:

    setPendingAction({type: 'addFavorite', value: 12});

    Then handling the login in the modal, the previous screen will stay mounted and keep its state.

    And then calling the pendingAction in the useEffect:

    useEffect(() => {
      if (isAuth) {
        if (pendingAction) {
          switch(pendingAction.type) {
            // do something
          }
          setPendingAction(undefined);
        }
      } else {
        // code runs when auth changes to false
      }
    }, [isAuth, pendingAction, setPendingAction]);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search