Polish
Polish

Reputation: 466

React Native screen navigation on API calls

So, I've been reacting for quite some time. I am facing a problem handling API and making it interact with small widgets in mobile app.

What I am trying to do ?

I am on a Screen(A) and on click of a button I go to Screen(B). Simple. Now in Screen(B) I fill up a form and submit it. While the form is submitting I have to show a Loading component. Finally the API responds if the request was "Success" or a "Failure".

If it was Success - Navigate back to Screen(A) and show a toast message(Boom..boom..) on screen(A).

If it Failed - Be in Screen(B) and show a toast message(yes, with a failure message).

My Approach

Let's start with reducers. I have following reducer state -

{
    forSubmitRequest: false, // false - API has been trigerred to submit form
    formSubmitRequestOver: true, // true - request is over
    formSubmitRequestStatus: true // true - success
}

Now my actions are as follows -

    case FORM_SUBMIT_REQUEST:
      return {
        ...state,
        formSubmitRequest: true,
        formSubmitRequestOver: false,
        formSubmitRequestStatus: false,
      };
    case FORM_SUBMIT_REQUEST_SUCCESS:
      return {
        ...state, 
        formSubmitRequestOver: true, 
        formSubmitRequestStatus: true
      };
    case FORM_SUBMIT_REQUEST_FAILED:
      return {
        ...state,
        formSubmitRequestOver: true,
        formSubmitRequestStatus: false,
      };
    case FORM_SUBMIT_REQUEST_DOWN:
      return {
        ...state, 
        formSubmitRequest: false, 
        formSubmitRequestOver: true
      };

Here's my coding logic in Screen(B)

const [formSubmitReq, setFormSubmitReq] = useState(false);
const [showErrorFormSubmitToast, setShowErrorFormSubmitToast] = useState(false);


useEffect(() => {
  if (showErrorFormSubmitToast) {
    Toast.show({
      type: 'error',
      text1: 'Error',
      text2: 'Could not submit.',
      topOffset: ResponsiveSize(0),
      onHide: () => {
        setShowErrorFormSubmitToast(false);
      },
    });
  }
}, [showErrorFormSubmitToast]);

if (
  formSubmitReq &&
  props.teacher.formSubmitRequest &&
  !props.teacher.formSubmitRequestOver
) {
  return <Loading msg="Submitting form..." />;
}
if (
  formSubmitReq &&
  props.teacher.formSubmitRequest &&
  props.teacher.formSubmitRequestOver
) {
  if (props.teacher.formSubmitRequestStatus) {
    props.navigation.goBack();
    return <></>;
  } else {
    setFormSubmitReq(false);
    setShowErrorFormSubmitToast(true);
    props.handleCreateFormSubmitDown();
  }
}

Logic in Screen(A)

const [showSuccessFormSubmitToast, setShowSuccessFormSubmitToast] =
    useState(false);

  useEffect(() => {
    if (showSuccessFormSubmitToast) {
      Toast.show({
        type: 'success',
        text1: 'Success',
        text2: 'Successfully submitted.',
        onHide: () => {
          setShowSuccessFormSubmitToast(false);
        },
      });
    }
  }, [showSuccessFormSubmitToast]);

  if (
    !showSuccessFormSubmitToast &&
    props.teacher.formSubmitRequest &&
    props.teacher.formSubmitRequestOver &&
    props.teacher.formSubmitRequestStatus
  ) {
    console.log('Prep show toast');
    setShowSuccessFormSubmitToast(true);
    props.handleCreateFormSubmitDown();
  }

Lastly this function - handleCreateFormSubmitDown just fires action - FORM_SUBMIT_REQUEST_DOWN

Gist of the code ->

I am trying to show Toast on Screen(A) only when request was success and request was actually fired. Not it may happen that request was success and I came back to Screen(A) now I simply navigate to Screen(B) so I have to make sure toast isn't visible as request wasn't fired. Now when reducer state updates then Screen(A) also gets rendered causing some nast things.

Can anyone point out what strategies they follow in such scenarios and where I could improve here?

Upvotes: 0

Views: 1931

Answers (1)

Pasindu Dilshan
Pasindu Dilshan

Reputation: 386

One way to do this is to utilize route params from react-navigation

In screen B

...
useEffect(() => {
  // Navigate to screen A with a route param
  navigation.navigate(A, { displaySuccessToast: true });

}, [showSuccessFormSubmitToast])

In Screen A

...
useEffect(() => {
  if (route.params.displaySuccessToast) {
    Toast.show({
        type: 'success',
        text1: 'Success',
        text2: 'Successfully submitted.',
        onHide: () => {
          // Hide Toast Action
        },
      });
  }
}, [route.params]);

Other wise you can use a global state management solution like redux

Its the same logic. You need to update a flag in the global state. Then navigate to the earlier screen and check if this flag is set and render the toast message.

Upvotes: 1

Related Questions