Search code examples
reactjsionic-frameworkroutesrenderhistory

In React/Ionic, how do I force my component to render when history.push is called (or rather when my URL changes)?


I'm building an Ionic 7 and a REact 18 application. I have this component with a submit button that pushes a route onto the history object (meant to hcange the URL) when a user clicks the Submit button

const OrderItemRecipientComponent: React.FC = () => {
    ...
  const history = useHistory();
  const [isButtonDisabled, setButtonDisabled] = useState(false);


  useEffect(() => {
    // This effect will run after the component re-renders
    if (isButtonDisabled) {
      // move on to the payment
      history.push("/payment");
    }
  }, [isButtonDisabled, history]);
  

  const handleSaveAndContinue = () => {
    setButtonDisabled(true); // Disable the button

    // add the item to the cart
    addToCart(orderItem);
  };

  return (
    <>
    ...
      <p>
        <AddressForm
          contactInfo={contactInfo}
          setContactInfo={setContactInfo}
        />
      </p>
      <IonButton expand="full" onClick={handleSaveAndContinue}  disabled={isButtonDisabled}>
        Pay
      </IonButton>
    </>
  );
};

export default OrderItemRecipientComponent;

and then I have this defined in my App.tsx routes

  <IonContent className="ion-padding" scroll-y>
    <IonRouterOutlet>
        ...
      <Route exact path="/payment">
        <PaymentContainer />
      </Route>
    </IonRouterOutlet>
  </IonContent>
</IonReactRouter>

THe issue is that often when I click the "Pay" button, although I see the route in my URL changes, I don't always see the PaymentContainer component rendered (the original compnent remains). When I click "Refresh" on my browser, I do see the correct component rendered. How can I correct my sequence so that the PaymentContainer component alawys renders when my route changes?


Solution

  • Based on joshua-wyllie's answer here which mentions this github issue: you need to have a wrapping <IonPage> on each of your pages (in your case as the root of PaymentContainer).

    If that doesn't solve the issue, you can try this as a workaround: As yairopro mentions in this post, you can try forcing an update like this:

    const history = useHistory();
    const [, forceUpdate] = useReducer(x => x + 1, 0);
    
    useEffect(() => {
      // This effect will run after the component re-renders
      if (isButtonDisabled) {
        // move on to the payment
        history.push("/payment");
        forceUpdate();
      }
    }, [isButtonDisabled, history]);