6
votes

I am new to React and Redux, I am actually creating a code of myself but I got stuck with a router kind of thing inside stateless component.

So, Actually I need to route to a component by using this.props.history.push('/somepath'). This is not happening inside a stateless component.

My Stateless component is

import React from "react"; // eslint-disable-line no-unused-vars
import "bootstrap/dist/css/bootstrap.min.css";
import "./header.css";

const Header = () => ({

    handleAuthor() {
        this.props.history('/somepath')// this is not working
    },

    render(){
        return (
            <div className = "header">
                <h1 onClick = {this.handleAuthor.bind(this)}>{this.props.headerText}</h1>
            </div>
        );
    } 
});

export default Header;

I am calling this inside another stateless component like mainlayout

import React from "react"; // eslint-disable-line no-unused-vars
import Header from "../header/Header"; // eslint-disable-line no-unused-vars
import Footer from "../footer/Footer"; // eslint-disable-line no-unused-vars
import "./mainLayout.css";

const MainLayout = props => ({
    render() {
        return (
            <div className="App">
                <Header headerText = "RK Boilerplate"/>
                <div className = "mainLayout">
                    <main>{props.children}</main>
                </div>
                <Footer />
            </div>
        );
    }
});

export default MainLayout;

My main file index.js looks like this

import React from "react"; // eslint-disable-line no-unused-vars
import ReactDOM from "react-dom"; // eslint-disable-line no-unused-vars
import { matchRoutes, renderRoutes } from "react-router-config"; // eslint-disable-line no-unused-vars
import { Router } from "react-router-dom"; // eslint-disable-line no-unused-vars
import { Switch } from "react-router"; // eslint-disable-line no-unused-vars
import { Provider } from "react-redux"; // eslint-disable-line no-unused-vars
import store from "./store"; // eslint-disable-line no-unused-vars
import routes from "./routes"; // eslint-disable-line no-unused-vars
import MainLayout from "./components/mainLayout/MainLayout"; // eslint-disable-line no-unused-vars

import createHistory from "history/createBrowserHistory";
let history = createHistory();
const App =  document.getElementById("app");

export default App;

ReactDOM.render(
    <Provider store={store}>
        <MainLayout>
            <Router history= {history}>
                <Switch>
                    {renderRoutes(routes)}
                </Switch>
            </Router>
        </MainLayout>                 
    </Provider>, 
    App);

SO what i need is I have to route from the header to another component where this component and path is given in a router file

router.js

import Home from "../containers/Home";
import About from "../containers/About";
import CreateUser from "../containers/CreateUser";

import Layout from "../containers/Layout";

const routes = [
    { path: "/",
        exact: true,
        component: Layout
    },
    { path: "/home",
        exact: true,
        component: Home
    },
    {
        path:"/About",
        exact: true,
        component: About
    },
    {
        path:"/createUser",
        exact: true,
        component: CreateUser
    }
];

export default routes;

I got an error like push of undefined , when i tried to route from header. Am I missing something is there any change that i should do here.

Thanks in advance.

4
You've probably known this but you did not pass props into your Header component, which is why you got the undefined error.. You can try it like this: const Header = (props) => {...}, and then access your history by props.history (without this). You can also use destructuring to make it look cleaner inside.ionizer

4 Answers

16
votes

In 2019, React Router v4 has now added the useHistory hook for stateless / functional components:

https://reacttraining.com/react-router/web/api/Hooks/usehistory

From the docs:

import { useHistory } from "react-router-dom";

function HomeButton() {
  let history = useHistory();

  function handleClick() {
    history.push("/home");
  }

  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}
2
votes

It worked for me by using withRouter, (plus ignoring typescript warning):

import { withRouter } from 'react-router-dom';

...

type Props = { myProp: boolean };

// @ts-ignore
export const MyComponent: FC<Props> = withRouter(({ myProp, history }) => {

...

})
1
votes

You can directly import the history object and push from that. For example try below code.

import React from "react"; // eslint-disable-line no-unused-vars
import "bootstrap/dist/css/bootstrap.min.css";
import "./header.css";
import history from "/your/history/path" //try this

const Header = () => ({

    handleAuthor() {
        history.push('/somepath')// change to this
    },

    render(){
        return (
            <div className = "header">
                <h1 onClick = {this.handleAuthor.bind(this)}>{this.props.headerText}</h1>
            </div>
        );
    } 
});

export default Header;

Create browser history like below and use it every where by importing.

import createBrowserHistory from 'history/createBrowserHistory';

export default createBrowserHistory({});
1
votes

Hope this doesn't come in too late. I successfully could redirect from a stateful component but I wanted to convert my component to a stateless component since the only thing that made it stateful was the redirect bit. I'm fairly new to react and most of the resources out there were not as clear. This is how I went about it.

import React from "react"; // eslint-disable-line no-unused-vars
import "bootstrap/dist/css/bootstrap.min.css";
import "./header.css";

const Header = (props) => {
    return (
        <div className = "header">
            <h1 onClick = {props.history.push('/some-path')}>{props.headerText}</h1>
        </div>
    );
} 

export default Header;