最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React history.push reloads component. Want it to load only once - Stack Overflow

programmeradmin2浏览0评论

When redirecting after ponent loads using history.push - my ponent is rendered again. Causing ponentDidMount() function to run twice.

Here's a simplified snippet of one of my ponents. I want the ponentDidMount() to run only once - and it works as expected without the history.push. But when i add the history.push - it loads twice. (Same happens if i use Redirect from react-router)

import * as React from "react";
import { history } from "../../configureServices";
import { explore } from "../../routes";

export class WeleComponent extends React.Component<object, object> {
  ponentDidMount() {
    // tslint:disable-next-line:no-console
    console.log("ponentDidMount");
    history.replace(explore);
  }
  render() {
    return <div />;
  }
}

Console:

ponentDidMount
ponentDidMount

Would love to find a way to have this run only once.

Edit: Thank you for the responses everyone. I'm going to post a quick code snippet and then post a Fiddle in a bit.

--- Update:

I am using React-Router. I build the history (along with some other services) in the configureServices.ts file.

// configureServices.ts
import { createBrowserHistory } from "history";

export const history = createBrowserHistory();

My index.ts looks like this:

import { history } from "./configureServices";

ReactDOM.render( 
  <Provider {...stores}> 
<AppComponent history={history} /> 
  </Provider>, 
document.getElementById("root") );

And my AppComponent which has all the routes looks like this:

import { History } from "history";
import { Route, Switch } from "react-router-dom";
import { Router } from "react-router-dom";
import * as Routes from "../../routes";

...
// Import Components
...

interface Props {
  history: History;
  ...
}

export class AppComponent extends React.Component<Props, {}> {
  ponentDidMount() {
    this.props.authStore && this.props.authStore.authenticate();
  }

  render() {
    return (
      <Router history={this.props.history}>
        // For toasts, please ignore for this example
        <ToastProvider
          placement={toastPlacement}
          autoDismissTimeout={toastDismissTimeout}
        >
            // Main App Div = Navbar + Components

          <div className="font-sans flex flex-col h-full text-phi-green-munsell bg-phi-gunmetal-rich-dark">
            <NavBarComponent />

            // This is where the routes are
            <div className="container mx-auto p-2 md:p-3 lg:p-4 justify-start">
              <Switch>
                <Route
                  exact={true}
                  path={Routes.homePage}
                  ponent={HomepageContainer}
                />
                <Route
                  exact={true}
                  path={Routes.logOut}
                  ponent={LogOutContainer}
                />
                <Route
                  exact={true}
                  path={Routes.wele}
                  ponent={WeleContainer}
                />
                <Route
                  path={Routes.explore}
                  ponent={ExploreComponent}
                />
                <Route
                  path={Routes.searchResults}
                  ponent={SearchResultsComponent}
                />
              </Switch>
            </div>
            <Footer />
            <DevTools position={mobxDevToolsPosition} />
          </div>
        </ToastProvider>
      </Router>
    );
  }
}

Thank you again for helping me with this.

When redirecting after ponent loads using history.push - my ponent is rendered again. Causing ponentDidMount() function to run twice.

Here's a simplified snippet of one of my ponents. I want the ponentDidMount() to run only once - and it works as expected without the history.push. But when i add the history.push - it loads twice. (Same happens if i use Redirect from react-router)

import * as React from "react";
import { history } from "../../configureServices";
import { explore } from "../../routes";

export class WeleComponent extends React.Component<object, object> {
  ponentDidMount() {
    // tslint:disable-next-line:no-console
    console.log("ponentDidMount");
    history.replace(explore);
  }
  render() {
    return <div />;
  }
}

Console:

ponentDidMount
ponentDidMount

Would love to find a way to have this run only once.

Edit: Thank you for the responses everyone. I'm going to post a quick code snippet and then post a Fiddle in a bit.

--- Update:

I am using React-Router. I build the history (along with some other services) in the configureServices.ts file.

// configureServices.ts
import { createBrowserHistory } from "history";

export const history = createBrowserHistory();

My index.ts looks like this:

import { history } from "./configureServices";

ReactDOM.render( 
  <Provider {...stores}> 
<AppComponent history={history} /> 
  </Provider>, 
document.getElementById("root") );

And my AppComponent which has all the routes looks like this:

import { History } from "history";
import { Route, Switch } from "react-router-dom";
import { Router } from "react-router-dom";
import * as Routes from "../../routes";

...
// Import Components
...

interface Props {
  history: History;
  ...
}

export class AppComponent extends React.Component<Props, {}> {
  ponentDidMount() {
    this.props.authStore && this.props.authStore.authenticate();
  }

  render() {
    return (
      <Router history={this.props.history}>
        // For toasts, please ignore for this example
        <ToastProvider
          placement={toastPlacement}
          autoDismissTimeout={toastDismissTimeout}
        >
            // Main App Div = Navbar + Components

          <div className="font-sans flex flex-col h-full text-phi-green-munsell bg-phi-gunmetal-rich-dark">
            <NavBarComponent />

            // This is where the routes are
            <div className="container mx-auto p-2 md:p-3 lg:p-4 justify-start">
              <Switch>
                <Route
                  exact={true}
                  path={Routes.homePage}
                  ponent={HomepageContainer}
                />
                <Route
                  exact={true}
                  path={Routes.logOut}
                  ponent={LogOutContainer}
                />
                <Route
                  exact={true}
                  path={Routes.wele}
                  ponent={WeleContainer}
                />
                <Route
                  path={Routes.explore}
                  ponent={ExploreComponent}
                />
                <Route
                  path={Routes.searchResults}
                  ponent={SearchResultsComponent}
                />
              </Switch>
            </div>
            <Footer />
            <DevTools position={mobxDevToolsPosition} />
          </div>
        </ToastProvider>
      </Router>
    );
  }
}

Thank you again for helping me with this.

Share Improve this question edited Jan 30, 2019 at 2:34 Panda asked Jan 29, 2019 at 17:13 PandaPanda 3694 silver badges15 bronze badges 4
  • Where is the history.push()? – stever Commented Jan 29, 2019 at 17:19
  • Is the WeleComponent also included in the explore route? – varoons Commented Jan 29, 2019 at 17:34
  • @stever: history is created in configureServices() (Updated in the answer) using export const history = createBrowserHistory(); – Panda Commented Jan 30, 2019 at 2:35
  • @varoons: WeleComponent is not in the explore route, currently its just a simple Pure.Component rendering text to test – Panda Commented Jan 30, 2019 at 2:36
Add a ment  | 

2 Answers 2

Reset to default 3

There are a couple of things that could cause your ponent to remount.

  1. If the react ponent tree above this ponent changes. This might be caused by something like having multiple Route ponents which display this ponent, but the path changes from one to the other. Even though the same ponent is ultimately displayed, the Route ponent which was matched changed.
  2. If the key for this ponent changed. If you are doing something like using randomly generated keys, or using array indices for keys and reordering elements, then you will see ponents remount.

I wanted to update the question since I figured it out. I was calling history.replace(explore) in ponentDidMount() - which (for reasons I don't understand well) - was causing the react ponent tree above this ponent to change as Matt H mentioned. I ended up using Redirect from react-router-dom and returning the redirect in render. Like:

render() {
    return <Redirect to={explore} />;
  }

So, I instead of making all calls in ponentDidMount() and redirecting in that function as well. I made the api calls in ponentDidMount() and used render to redirect. Happy it worked and thank you all for responding to my question.

发布评论

评论列表(0)

  1. 暂无评论