0

Using React 16 with Typescript. Inside a click handler method in app.tsx, I need to redirect, so that the redirection will happen from any screen in the app. But cannot use this.props.history.push in app.tsx. We have used BrowserRouter in app.tsx. I also need similar redirection from a Modal component as well, but it seems like history is not available throughout the application (incl. app.tsx). Is there a way to achieve this? I have tried many different things, nothing works. I need to make history.push available to the entire app, to each component, including app.tsx...is this possible?

This is my app.tsx (copied from original, non-generic parts replaced by ...)

import * as React from 'react'
import { BrowserRouter as Router } from 'react-router-dom';
import { withRouter } from 'react-router-dom';
import {RouteComponentProps} from "react-router";
....

export interface DispatchProps {
....
}

export interface AppProps {
loading?: boolean;
...
}

interface State {
...
}


type Props = DispatchProps & AppProps & RouteComponentProps<{}>;

export class App extends React.Component<Props, State> {
    constructor(props: Props) {
        super(props);

        this.state = {
            ...
        }
    }

    render() {
        ...
        return (
            <div>
                <Router>
                    <div>
                        <div id="header"></div>
                        .....
                    </div>
                </Router>
                <Footer />
            </div>
        )

    }
}

export default withRouter(App);

Here is my routes.tsx (copied from original, non-generic parts replaced by ...)

    import * as React from 'react';
    import { NavLink } from 'react-router-dom';
    import { Route, Redirect, Switch, RouteComponentProps, RouteProps } from 'react-router';

    import withBreadcrumbs, {
      BreadcrumbsRoute,
      InjectedProps,

    } from 'react-router-breadcrumbs-hoc';

    ...

    const routes: BreadcrumbsRoute[] = [
      { path: '/not-found', breadcrumb: '404' },
      { path: '/path1', breadcrumb: 'component1' },
      { path: '/path2', breadcrumb: 'component2' },
        ...  
    ];

    const Breadcrumbs = ({ breadcrumbs }: InjectedProps) => (
    ...
    )

    export const Routes = () => (
      <div>
        <Switch>
            <Route exact={true} path="/not-found" component={NotFound} />
            <Route exact={true} path="/" component={Home} />
            <Route
              exact={true}
              path="/some-path"
              component={SomeComponent}
           />
          <PrivateRoute
            exact={true}
            path="/some-other-path/:some-parameter"
            component={SomeOtherComponent}
          />
          ...
          <Redirect to="/not-found" />
        </Switch>
      </div>
  ); 

    export const x = withBreadcrumbs(routes, { disableDefaults: true })(Breadcrumbs);

    const PrivateRoute = ({ component, ...rest }: RouteProps) => {
        ...
        const render = (props: RouteComponentProps<{}>): React.ReactNode => {
            ...
        }   
    } 

    export default Routes;
    export { x as breadcrumb };
Souvik
  • 1,027
  • 8
  • 13
  • you can refer this https://stackoverflow.com/questions/53539314/what-is-withrouter-for-in-react-router-dom – elvis_ferns Feb 05 '20 at 14:42
  • see also https://stackoverflow.com/questions/42701129/how-to-push-to-history-in-react-router-v4 – Squiggs. Feb 05 '20 at 14:43
  • @Squiggs.using BrwoserRouter....can not change that. – Souvik Feb 06 '20 at 13:19
  • @elvis_ferns Thanks....if I add withRouter(App), then index.tsx is throwing error. The error is like "{} is missing location, match..." etc. Tried adding RouteComponentProps in App component, still error is showing. Trying with npm package 'react-router-global-history', which does not have typescript types. struggling with declare module. – Souvik Feb 06 '20 at 13:23
  • @Souvik please share a snippet of your App.tsx and Routes.tsx – elvis_ferns Feb 07 '20 at 08:12
  • @elvis_ferns Added in the question. – Souvik Feb 07 '20 at 09:06

3 Answers3

0

If you want this.props.history.push then you have to export your component with withRouter HOC.

Ashish
  • 410
  • 2
  • 11
0

Hi I think you don't need the Router component in App normally with withRouter HOC it has

Lorick
  • 11
  • 1
0

I solved the problem by installing a npm package. There was a post here in SOF on the same issue, and the author gave link to the npm package s/he created. Sadly, could not find the original post. It is only for ReactJS, and I have just made it usable in React+TS. The npm package is react-router-global-history. Below are my code snippets:

This is a newly created file since @types is not available for the above package

src/react-router-global-history.d.ts

/// <reference types="node" />
/// <reference types="react" />
/// <reference types="react-dom" />

// import { any } from 'expect';
import { History } from 'history'

declare module 'react-router-global-history' {
    export const ReactRouterGlobalHistory: React.ComponentType<any>;
    export default function getHistory(): History;
}

This is my app.tsx (copied from original, non-generic parts replaced by ellipsis)

src/app.tsx

import * as React from 'react'
import { BrowserRouter as Router } from 'react-router-dom';
import { withRouter } from 'react-router-dom';
import {RouteComponentProps} from "react-router";
...
import { ReactRouterGlobalHistory } from 'react-router-global-history';
import getHistory from 'react-router-global-history';
...

export interface DispatchProps {
....
}

export interface AppProps {
loading?: boolean;
...
}

interface State {
...
}


type Props = DispatchProps & AppProps & RouteComponentProps<{}>;

export class App extends React.Component<Props, State> {
    constructor(props: Props) {
        super(props);

        this.state = {
            ...
        }
    }

    render() {
        ...
        return (
            <div>
                <Router>
                    <div>
                        <ReactRouterGlobalHistory />
                        <div id="header"></div>
                        .....
                    </div>
                </Router>
                <Footer />
            </div>
        )

    }
    ...
    onClickHandler(someParam: string, event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
        event.preventDefault();
        ....
        getHistory().push('/some-path');
    }
}

export default App;

PS: My app was created using create-react-app

Souvik
  • 1,027
  • 8
  • 13