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
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
Thank you. This simply solved my problem !
– Jiah827
Sep 5 '18 at 5:14