简体   繁体   中英

React Router history.push in infinite loop

I have a page ("/paymentsucess"). In this page, I am using the react-countdown-circle-timer component ( https://github.com/vydimitrov/react-countdown-circle-timer#props-for-both-reactreact-native ). Upon reaching this page ("/paymentsuccess"), countdown beings. After countdown reaches zero, I want to redirect user back to home page ("/").

To achieve this, for the CountdownCircleTimer component, when onComplete, I set the state initialMount to false.

            <CountdownCircleTimer
              onComplete={() => {
                setInitialMount(false);
                return [true, 1500];
              }}
              isPlaying
              duration={2}
              colors={[
                ["#004777", 0.33],
                ["#F7B801", 0.33],
                ["#A30000", 0.33],
              ]}
            >
              {renderTime}
            </CountdownCircleTimer>

Given that initialMount is changed, my useEffect (in the paymentsuccess component) will kick in and redirect users to "/". I am using history.push("/") here.

  useEffect(() => {
    if (initialMount !== true) {
      console.log("On change in status,");
      console.log(initialMount);
      history.push("/");
    }
  }, [initialMount, history]);

I was able to redirect user back to "/" successfully. But upon reaching "/", they got redirected back to /paymentsuccess again. And then from /paymentsuccess it goes back to / and then the loops continue. Infinite loop.

Any idea what I am doing wrong here? :( I need to stop this loop and lands user back to / and stops there.

I am using Router from react-router-dom and createBrowserHistory from history.

Below is the full code for my paymentsuccess component

import React, { useEffect, useStatem} from "react";
import { useHistory } from "react-router-dom";
import { makeStyles } from "@material-ui/core/styles";
import Grid from "@material-ui/core/Grid";
import Paper from "@material-ui/core/Paper";
import { CountdownCircleTimer } from "react-countdown-circle-timer";

function PaymentSuccess() {
  const useStyles = makeStyles((theme) => ({
    root: {
      flexGrow: 1,
    },
  }));

  const classes = useStyles();
  const history = useHistory();
  const [initialMount, setInitialMount] = useState(true);

  useEffect(() => {
    console.log("On component mount, status is");
    console.log(initialMount);
  }, []);

  useEffect(() => {
    return () => {
      console.log("On component unmount, status is");
      setInitialMount(true);
      console.log(initialMount);
    };
  }, []);

  useEffect(() => {
    if (initialMount !== true) {
      console.log("On change in status,");
      console.log(initialMount);
      history.push("/");
    }
  }, [initialMount, history]);

  const renderTime = ({ remainingTime }) => {
    if (remainingTime === 0) {
      return <div className="timer">Starting...</div>;
    }
    return (
      <div className="timer">
        <div className="value">{remainingTime}</div>
      </div>
    );
  };

  return (
    <div className={classes.root}>
      <Grid container spacing={0}>
        <Grid item xs={6} sm={6}>
          <Paper
            className="paymentSuccessLeftPaper"
            variant="outlined"
            square
          ></Paper>
        </Grid>
        <Grid item xs={6} sm={6}>
          <Paper className="paymentSuccessRightPaper" variant="outlined" square>
            <h1>Payment Success</h1>
            <CountdownCircleTimer
              onComplete={() => {
                setInitialMount(false);
                return [true, 1500];
              }}
              isPlaying
              duration={2}
              colors={[
                ["#004777", 0.33],
                ["#F7B801", 0.33],
                ["#A30000", 0.33],
              ]}
            >
              {renderTime}
            </CountdownCircleTimer>
          </Paper>
        </Grid>
      </Grid>
    </div>
  );
}

export default PaymentSuccess;

I have checked my "/" page and I don't think there is any logic there redirecting to "/paymentsuccess". The page ("/") code is as below.

import React from "react";

import { makeStyles } from "@material-ui/core/styles";
import Grid from "@material-ui/core/Grid";
import Paper from "@material-ui/core/Paper";
import Button from "@material-ui/core/Button";
import Link from "@material-ui/core/Link";

function LandingPage() {
  const useStyles = makeStyles((theme) => ({
    root: {
      flexGrow: 1,
    },
    paper: {
      minHeight: "100%",
      padding: theme.spacing(0),
      textAlign: "center",
      color: theme.palette.text.secondary,
    },
  }));

  const classes = useStyles();

  return (
    <div className={classes.root}>
      <Grid container spacing={0}>
        <Grid item xs={4} sm={4}>
          <Paper className={classes.paper} variant="outlined" square>
            <h1>Photo Strips</h1>
            <Button variant="contained" color="primary">
              <Link href="/photo10">SELECT</Link>
            </Button>
          </Paper>
        </Grid>
        <Grid item xs={4} sm={4}>
          <Paper className={classes.paper} variant="outlined" square>
            <h1>Photo Strips and GIF</h1>
            <Button variant="contained" color="primary">
              <Link href="/photogif12">
                SELECT
              </Link>
            </Button>
          </Paper>
        </Grid>
        <Grid item xs={4} sm={4}>
          <Paper className={classes.paper} variant="outlined" square>
            <h1>Photo Strips and Boomerang</h1>
            <Button variant="contained" color="primary">
              <Link href="/photoboomerang12">
                SELECT
              </Link>
            </Button>
          </Paper>
        </Grid>
      </Grid>
    </div>
  );
}

export default LandingPage;

Thank you all in advance! Appreciate all the help and advise

UPDATE

Below is Router code

import React from "react";
import { Router, Switch } from "react-router-dom";

import LandingPage from "./components/LandingPage";
import Photo10 from "./components/Photo10";
import PhotoGIF12 from "./components/PhotoGIF12";
import PhotoBoomerang12 from "./components/PhotoBoomerang12";
import PaymentSuccess from "./components/PaymentSuccess";

import DynamicLayout from "./router/DynamicLayout";

import { history } from "./helpers/history";

const App = () => {
  return (
    <Router history={history}>
      <div className="App">
        <Switch>
          <DynamicLayout
            exact
            path="/"
            component={LandingPage}
            layout="LANDING_NAV"
          />
          <DynamicLayout
            exact
            path="/photo10"
            component={Photo10}
            layout="PHOTO10_PAGE"
          />
          <DynamicLayout
            exact
            path="/photogif12"
            component={PhotoGIF12}
            layout="PHOTOGIF12_PAGE"
          />
          <DynamicLayout
            exact
            path="/photoboomerang12"
            component={PhotoBoomerang12}
            layout="PHOTOBOOMERANG12_PAGE"
          />
          <DynamicLayout
            exact
            path="/paymentsuccess"
            component={PaymentSuccess}
            layout="PAYMENTSUCCESS_PAGE"
          />
        </Switch>
      </div>
    </Router>
  );
};

export default App;

Below is the code for the DynamicLayout component

import React from "react";

const DynamicLayout = (props) => {
  const { component: RoutedComponent, layout } = props;

  const actualRouteComponent = <RoutedComponent {...props} />;

  switch (layout) {
    case "LANDING_NAV": {
      return <>{actualRouteComponent}</>;
    }

    case "PHOTO10_PAGE": {
      return <>{actualRouteComponent}</>;
    }

    case "PHOTOGIF12_PAGE": {
      return <>{actualRouteComponent}</>;
    }

    case "PHOTOBOOMERANG12_PAGE": {
      return <>{actualRouteComponent}</>;
    }

    case "PAYMENTSUCCESS_PAGE": {
      return <>{actualRouteComponent}</>;
    }

    default: {
      return (
        <>
          <h2>Default Nav</h2>
          {actualRouteComponent}
        </>
      );
    }
  }
};

export default DynamicLayout;

This problem occurs when you changes value of variable in useEffect and that variable also added in useEffect dependency array, So when ever your useEffect change the value due to presence of that variable in dependency array, it again called the useEffect thus a infinite loop occurs

so just remove 'history' variable from your dependency array

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM