0

After spending time with withRouter and connect methods, I'm still unable to figure out why my view isn't updating with change in URL.

When I navigate from "/" to "/about", page doesn't update, though works fine on reloading.

From React DevTools, I can see that my props.location doesn't change even after redirection. So my guess is that I have messed up the implementation of Redux somewhere.

App.js

import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";

import Main from "./Main";

const actionCreators = {};

function mapStateToProps(state) {
    return state;
}

function mapDispatchToProps(dispatch) {
    const actions = bindActionCreators(actionCreators);

    return { ...actions, dispatch };
}

const App = withRouter(connect(mapStateToProps, mapDispatchToProps)(Main));

export default App;

Main.js

import React from "react";

import Navbar from "./components/navbar/navbar.component";
import Footer from "./components/footer/footer.component";

const Main = props => (
    <div>
        <Navbar currentState="Home" />
        {React.cloneElement(props.children, props)}
        <Footer />
    </div>
);

export default Main;

index.js

import React from "react";

import { Provider } from "react-redux";
import { render } from "react-dom";
import { Router, Route, Switch } from "react-router";
import { withRouter } from "react-router-dom";

import store, { history } from "./store";

import App from "./App";
import Home from "./containers/home/home.component";
import AboutPage from "./containers/aboutPage/aboutPage.component";

const MOUNT_POINT = document.getElementById("root");

const router = (
    <Provider store={store}>
        <Router history={history}>
            <App>
                <Switch>
                    <Route exact path="/" component={Home} />
                    <Route path="/about" component={AboutPage} />
                </Switch>
            </App>
        </Router>
    </Provider>
);

render(
    router,
    MOUNT_POINT,
);

Though I am getting the following diff in Redux state (as below), but same is not being reflected in React State.

{
    "type": "@@router/LOCATION_CHANGE",
    "payload": {
        "pathname": "/about",
        "search": ","
        hash ":",
        "key": "wk0oya"
    }
}

I believe I have somewhere messed up linking redux with react-router. Had tried the withRouter solution credits: https://stackoverflow.com/a/45036930/2302156.

I also tried passing options to connect method from react-redux as per following API Guide:

[pure] (Boolean): If true, connect() will avoid re-renders and calls to mapStateToProps, mapDispatchToProps, and mergeProps if the relevant state/props objects remain equal based on their respective equality checks. Assumes that the wrapped component is a “pure” component and does not rely on any input or state other than its props and the selected Redux store’s state. Default value: true

My list of package dependencies:

"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-redux": "^5.0.7",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"react-router-redux": "^4.0.8",
"redux": "^4.0.0",
"redux-thunk": "^2.3.0"

Anyone who can help me fix this?

Shreesh Katyayan
  • 101
  • 3
  • 14

2 Answers2

0

I believe that in Main.js you should use {this.props.children} instead of {React.cloneElement(props.children, props)}. React.cloneElement works properly if your child is a single React element and your Main.js looks more like layout (wrapper) for page content.

import React from "react";

import Navbar from "./components/navbar/navbar.component";
import Footer from "./components/footer/footer.component";

const Main = ({ children }) => (
    <div>
        <Navbar currentState="Home" />
        {children}
        <Footer />
    </div>
);

export default Main;
CodeMeNatalie
  • 124
  • 1
  • 8
  • Hey, I have tried that but of no help. Also, please wrap `({ children })` with a pair of braces :) – Shreesh Katyayan Dec 13 '18 at 15:23
  • Oh right, thanks! Hmm, could you provide `codesandbox` version to debug it easier? – CodeMeNatalie Dec 13 '18 at 15:42
  • @ShreeshKatyayan well I looked into it a bit more and I think you've got bad structure inside the router. Inside `index.js` you could have structure like this imo. Then you shouldn't need to use `withRouter()`. As far as I checked `withRouter` is messing your state. Could you try something like this? You shouldn't need here App component at all. https://jsfiddle.net/s56p4n3o – CodeMeNatalie Dec 13 '18 at 16:13
  • I'm in transit currently. Will try out and get back within a couple of hours max. Thanks for all the effort mate! – Shreesh Katyayan Dec 13 '18 at 16:19
  • Sure, tag me when you've checked it -> https://jsfiddle.net/s56p4n3o/2/ (fixed header and footer issue) – CodeMeNatalie Dec 13 '18 at 16:27
0

This was not working because of wrong dependency included.

Changes in index.js,

import React from "react";

import { Provider } from "react-redux";
import { render } from "react-dom";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";

import store from "./store";

import App from "./App";
import Home from "./containers/home/home.component";
import AboutPage from "./containers/aboutPage/aboutPage.component";

const MOUNT_POINT = document.getElementById("root");

const router = (
    <Provider store={store}>
        <Router>
            <App>
                <Switch>
                    <Route exact path="/" component={Home} />
                    <Route path="/about" component={AboutPage} />
                </Switch>
            </App>
        </Router>
    </Provider>
);

render(
    router,
    MOUNT_POINT,
);
Shreesh Katyayan
  • 101
  • 3
  • 14