react-router-dom link works in app.js(parent component) but doesn't work in child component

react-router-dom link works in app.js(parent component) but doesn't work in child component



I have 'Nav' component in 'app.js' ( parent component ) and 'home.js' conditionally to have white space responsively on the bottom of the header only in Homepage by setting header height: 90vh .


header height: 90vh



In order to do that, I included < Nav > in header tag in 'Home.js'.



And Here the problem came up,
Nav Link works well in app.js, but it's not even clickable in home.js.



Homepage Header Image



index.js


import React from 'react';
import render from 'react-dom';
import Provider from 'react-redux';
import ConnectedRouter as Router from 'react-router-redux';
import createHistory from 'history/createBrowserHistory';
import Store from './Store';
import Routes from './Routes';

require('./styles/main.scss');

const root = document.createElement('div');
document.body.appendChild(root);

render(
<Provider store=Store>
<Router history=createHistory()>
<Routes />
</Router>
</Provider>,
root,
);



Routes.js


import React from 'react';
import Switch, Route from 'react-router-dom';
import hot from 'react-hot-loader';
import App from './src/app';
/* --- Components --- */
import Loader from './src/shared/loader';

const Home = Loader(
loader: () => import('./src/components/Home' /* webpackChunkName: 'Home' */),
);

const Login = Loader(
loader: () => import('./src/components/login' /* webpackChunkName: 'Login' */),
);

const NoMatch = Loader(
loader: () => import('./src/shared/NoMatch' /* webpackChunkName: 'NoMatch' */),
);

const routes = () => (
<div>
<App />
<Switch>
<Route exact path="/" component=Home />
<Route path="/login" component=Login />
<Route component=NoMatch />
</Switch>
</div>
);

const Routes =
!module.hot || process.env.NODE_ENV === 'production'
? routes
: hot(module)(routes);

export default Routes;



App.js


import React from 'react';
import Helmet from 'react-helmet';
/* --- shared --- */
import Loader from './shared/loader';

const Nav = Loader(
loader: () => import('./shared/nav' /* webpackChunkName: 'Nav' */),
);

const App = props =>
const isHomepage = window.location.pathname === '/';

return (
<div id="app">
<Helmet>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>###</title>
<meta property="og:title" content="###" />
<meta property="og:description" content="###" />
<meta property="og:type" content="###" />
<meta property="og:url" content="###" />
<meta property="og:image" content="###" />
<link type="text/plain" rel="author" href="http://domain/humans.txt" />
<link type="text/plain" rel="author" href="http://domain/robots.txt" />
<link
href="https://fonts.googleapis.com/css?family=Nanum+Gothic"
rel="stylesheet"
/>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"
/>
</Helmet>
props.children
!isHomepage ? <Nav /> : null
</div>
);
;

export default App;



nav.js


import React from 'react';
/* --- shared --- */
import * as data from './data';
import Ul from './ul';

const Nav = () => (
<div className="nav">
<div className="flex justify-between nav--top">
<p className="mh-auto f-mini fw3">
상담전화
<span className="f-regular"> xxx-xxxx-xxxx</span>
</p>
<Ul links=data.redirectToLogin />
</div>
<h1>
<Ul links=data.redirectToHome />
</h1>
<div className="hr-center">
<Ul links=data.nav />
</div>
</div>
);

export default Nav;



ul.js


import React from 'react';
import Link from 'react-router-dom';

const Ul = ( links ) => (
<ul className="nav-menu">
links &&
links.map(e => (
<li>
<Link className=e.className key=e.id to=e.to>
e.name
</Link>
</li>
))
</ul>
);

export default Ul;



Home.js


import React from 'react';
/* --- Components --- */
import HomeMain from './Home.main';
/* --- Shared --- */
import Nav from '../shared/nav';

const Home = () => (
<div>
<header>
<Nav />
<div className="header-text--box">
<h2>
<span className="f-regular f-en lh-3">NO MSG!</span>
<br />
오늘도 열심히 일하는 당신에게 착한 가격의 집밥을 선물하세요.
</h2>
</div>
</header>
<HomeMain />
</div>
);

export default Home;



Version


react: 16.4.2
react-dom: 16.4.2
react-redux: 5.0.7
react-router-dom: 4.3.1
react-router-redux: 5.0.0-alpha.9



Thank you for taking your time to help me out.




2 Answers
2



Looking at your styling, it seems the header has a negative z-index.


header


z-index



By setting a negative z-index, this is likely to interfere with children of the <header> (ie your <nav> component), from receiving click events and/or responding to the cursor correctly.


<header>


<nav>



I would recommend removing z-index: -1; from your header.scss to address your problem. Hope that helps!


z-index: -1;


header.scss






Thank you. This simply solved my problem !

– Jiah827
Sep 5 '18 at 5:14






Glad I could help :-)

– Dacre Denny
Sep 5 '18 at 5:14



I'll make a simplified example here of setup that I normally use. So, what about this approach?



index.js


import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import Provider from "react-redux/es/components/Provider";
import createStore, applyMiddleware from 'redux';
import rootReducer from '../reducers/rootReducer';
import thunk from 'redux-thunk';

// Usually I would do this in an external file, but here I'm configuring my store

const myStore = configureStore(initialState)
return createStore(
rootReducer,
initialState,
applyMiddleware(thunk)
);


// After that, I'm wrapping my App component inside of the Provider and passing in the configured store

ReactDOM.render((
<Provider store=myStore >
<App/>
</Provider>
), document.getElementById('root'));



App.js


import React, Component from 'react';
import BrowserRouter from 'react-router-dom'
import PrimaryLayoutContainerComponent from "../containers/PrimaryLayoutContainer";

// In my App.js I'm wrapping my primary layout container with BrowserRouter to get access to the history and also passing in the props

class App extends Component
render()
return (
<BrowserRouter>
<PrimaryLayoutContainerComponent ...this.props/>
</BrowserRouter>
);


export default App;



PrimaryLayoutContainerComponent.js

In this (main container) I would take the full advantage of my previous configs as well as whatever is offered and needed regarding the Redux state management. I also use withRouter at this stage to get access to the history object's properties.


import React from 'react';
import connect from 'react-redux';
import bindActionCreators from 'redux';
import * as myActions from '../actions';
import PrimaryLayout from "../components/layout/PrimaryLayout";
import withRouter from 'react-router';
import PropTypes from 'prop-types';


class PrimaryLayoutContainerComponent extends Component
render()
return (
<div>
//Here we pass our history as props
<PrimaryLayout history=this.props.history
propsX=this.props.propsX

propsY=this.props.actions.propsY
/>
</div>
)



// In these (and all other cases) I would highly recommend using propTypes.
// They could give you the answer in where the issues might be in your future development

PrimaryLayoutContainerComponent.propTypes =
loggedUser: PropTypes.string,
actions: PropTypes.object.isRequired
;

const mapStateToProps = (state) =>
return xxxx


const mapDispatchToProps = (dispatch) =>
return
actions: bindActionCreators(myActions, dispatch)
;


export default withRouter(connect(mapStateToProps, mapDispatchToProps)(PrimaryLayoutContainerComponent));



...and then finally in my Primary Layout Component I would define all my routes like this:


Primary Layout Component



PrimaryLayoutComponent.js


import React, Component from 'react';
import Switch, Route, Redirect, Link from 'react-router-dom';
// ... import all my compoenents


class PrimaryLayout extends Component
constructor(props)
super(props);
this.state =
currentRoute: '' // I would use the state to dynamically change the
// routes depending on which one was clicked





componentWillReceiveProps(nextProps)
this.setState(
currentRoute: nextProps.history.location.pathname
)


componentWillMount()
this.setState(
currentRoute: this.props.history.location.pathname
)


render()

const currentRoute = this.state;

return (
<div className="wrapper">
<header className="xxxx" role="banner">
<div className="container">
<div className="xxxxx">


<Link to="/home">
<img src=logo alt="your logo"/> Your App Name
</Link>
<ul className="navbar__menu">
<li className=currentRoute === "/home" ? "active" : "">
<Link to="/home"> Home </Link>
</li>

<li className=currentRoute === "/componentOne" ? "active" : "">
<Link to="/componentOne"> componentOne</Link>
</li>

<li className=currentRoute === "/componentTwo" ? "active" : "">
<Link to="/componentTwo"> componentTwo</Link>
</li>
</ul>

</div>
</div>
</header>

// At the very end, I'm using the Switch HOC and defining my routes inside of a main tag

<main>
<Switch>
<Route path='/home' component=HomeContainerComponent />
<Route path='/componentOne' component=componentOne />
<Route path='/componentTwo' component=componentTwo />
<Redirect to="/home"/>
</Switch>
</main>
</div>
)



export default PrimaryLayout;



I hope my approach was helpful to you and if you have any further questions, please let me know. I'll answer them ASAP






Hi @Bigga_HD, Thanks for your answer. Learning from your code, My code is now passing history as props and i am also thinking of using state to keep track of routes. I was wondering why you are using componentWillReceivepRrops() methods in PrimaryLayoutComponent.js. ComponentWillMount() Method updates the state based on props change.

– Jiah827
Sep 5 '18 at 11:06







@Jiah827 - componentWillMount is called once at first render. componentWillReceiveProps is called for subsequent renders. The problem is I don't know for sure if the prop will be initialized by the time the first render is called. (The prop depends on asynchronous data). So - I can't put the code in componentWillMount. But if I put it in componentWillReceiveProps and then change something higher up the component chain so that the data is fulfilled synchronously now my code in componentWillReceiveProps is never run.

– Bigga_HD
Sep 5 '18 at 18:53


componentWillMount


componentWillReceiveProps






That's just how I usually used to deal with async data and HOC. If componentWillMount works for your situation, great, use that one only :) If my code was of any help, please consider at least an upvote. Thanks. But I wouldn't worry about, componentWillReceiveProps is deprecated and will be removed in the next major version. - > React 17 ... for more info, I would suggest reading this post. reactjs.org/blog/2018/03/27/update-on-async-rendering.html

– Bigga_HD
Sep 5 '18 at 18:57



componentWillMount


componentWillReceiveProps






I see. Thank you Bigga_HD !! I've already upvoted your answer but apparently it doesn't change publicly displayed post score since i don't have enough reputation yet :/

– Jiah827
Sep 7 '18 at 16:04







Don't worry about it. I was kinda joking. I'm just glad it was helpful ;)

– Bigga_HD
Sep 7 '18 at 16:35



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)