I had this working before, but I've made some changes in my app structure which has broken the routes. If I manually go to the route in the browser it works (the correct content loads). The href attribute is not rendering in the html.
I have a warning message in my console:
Warning: Failed prop type: Invalid prop to supplied to Link.
I don't nderstand why it's invalid.
What can I do to improve the code and fix the problem?
Index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import Header from './Header';
import Routes from './Routes';
import '../less/imports.less';
const App = () => (
<div>
<Header />
<main>
<Routes />
</main>
</div>
);
if (typeof window !== 'undefined') {
ReactDOM.render(
(
<App />
), document.getElementById('app'),
);
}
Routes.jsx:
import React from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import Dashboard from './Dashboard';
import About from './About';
import Blog from './Blog';
class Routes extends React.Component {
constructor(props) {
super(props);
this.state = {
active: 'active',
};
}
render() {
return (
<Router>
<div>
<nav>
<ul className="block-group">
<li className={this.state.active}><Link to={Dashboard}>Dashboard</Link></li>
<li><Link to={About}>About</Link></li>
<li><Link to={Blog}>Blog</Link></li>
</ul>
</nav>
<Route exact path="/" component={Dashboard} />
<Route path="/about" component={About} />
<Route path="/blog" component={Blog} />
</div>
</Router>
);
}
}
export default Routes;
I have just fixed this by changing the to href to the actual route strings. Not sure how it worked before.
<li className={this.state.active}><Link to="/">Dashboard</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/blog">Blog</Link></li>
Related
new to React Router, my question is how to render a particular component inside other layout which is already rendered (i have two components sidebar and content i just want if i click on any link in sidebar that component will we render in already render Content component not override that)
////////////Sidebar.js////////////
import React from 'react'
import { BrowserRouter, Link } from 'react-router-dom'
import PersonalImg from '../images/personal.gif'
const Sidebar = () => {
return (
<div className="sidebar">
<BrowserRouter>
<div className="personal-img">
<img src={PersonalImg} alt="personl-img" />
</div>
<div className="navigation">
<ul className="list">
<li><Link to="/about">About</Link></li>
<li><Link to="/work">Work</Link></li>
<li><Link to="/skills">Skills</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</div>
</BrowserRouter>
</div>
)
}
export default Sidebar;
Content component...
/////////////////Content.js//////////////////
import React from 'react'
import { BrowserRouter, Route } from 'react-router-dom'
import About from './About'
import Skills from './Skills'
import Work from './Work'
import Contact from './Contact'
const Content = (props) => {
return (
<div className="content">
<BrowserRouter>
<Route path="/" componet={About} />
<Route path="/work" componet={Work} />
<Route path="/contact" componet={Contact} />
<Route path="/skills" componet={Skills} />
</BrowserRouter>
</div>
)
}
export default Content;
and thats how App.js rendering these components
render() {
return (
<Fragment>
<Sidebar />
<Content />
</Fragment>
)
}
Here, I have created small demo for you
https://codesandbox.io/s/naughty-glade-vnj0l
Problem 1: componet spell is wrong. It should be component in the Route.
Problem 2: set exact keyword for the first route like this <Route exact path="/" componet={About} />.
Use single BrowserRouter throughout the application.
I am very new to react-routing. After reading the docs and reading some articles this is how structured my routing. Please correct me if I am doing wrong.
Using react-router V4
Routes.js
import React from 'react';
import App from '../app/components/App';
import Dashboard from '../dashboard/components/Dashboard';
import Contact from '../dashboard/components/Contact';
import Account from '../dashboard/components/Account';
import Career from '../dashboard/components/Career';
import NoMatch from './NoMatch';
import { Provider } from 'react-redux';
import { Route, BrowserRouter, Switch, Redirect } from 'react-router-dom';
const Root = ({ store }) => (
<Provider store={store}>
<BrowserRouter>
<div>
<Route path="/app" component={App} />
<Switch>
<Route path="/app" exact component={Dashboard} />
<Route path="/app/home/dashboard" component={Dashboard} />
<Route path="/app/home/contact" component={Contact} />
<Route path="/app/home/account" component={Account} />
<Route path="/app/home/career" component={Career} />
<Route component={NoMatch} />
</Switch>
</div>
</BrowserRouter>
</Provider>
)
export default Root
I used /app 2 times. First is to load always as it has sidenav and header. Then inside switch I used to load default component dashboard.
App.js
import React, { Component } from 'react';
import 'bootstrap/dist/css/bootstrap.css';
import 'font-awesome/css/font-awesome.min.css';
import Header from './Header';
import SideNav from './SideNav';
class AppComp extends Component {
componentDidMount() {
const { match: { params } } = this.props;
}
render() {
return (
<div>
<div className="container body">
<div className="main_container">
<Header />
<SideNav routeparams={this.props}/>
</div>
</div>
</div>
);
}
}
export default AppComp;
Sidenav.jsx
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom'
import '../../css/sidenav.css';
class SideNav extends Component {
render() {
console.log(this.props.routeparams);
return (
<div className="col-md-3 left_col">
<div className="left_col">
<div className="clearfix"></div>
<div id="sidebar-menu">
<div className="menu">
<ul className="nav side-menu">
<li>
<NavLink to="/app/home/dashboard">Home</span></NavLink>
<ul>
<li className="current-page">
<NavLink to="/app/home/dashboard" activeClassName="current">Dashboard</NavLink>
</li>
<li>
<NavLink to="/app/home/contact" activeClassName="current">Contact</NavLink>
</li>
<li>
<NavLink to="/app/home/account" activeClassName="current">Account</NavLink>
</li>
<li>
<NavLink to="/app/home/career" activeClassName="current">Career</NavLink>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
);
}
}
export default SideNav;
I have two issue :
this.props.routeparams in sidenav logged twice which means sidenav rendered twice . this is happening after adding routing . Also this.props.routeparams match path is always /app, which I think because sidenav is a child component of app component. How can I fix this ? I want to get current route path in sidenav.
activeClassName="current" gets applied to correct navlink but the css style gets reflected only if I click somewhere in the page. Seems so strange. I can resolve that issue if I get current match.path at sidenav component then I will do it custom way without activeClassName.
Any help would be greatly appreciated.
I have used react-router-dom with webpack and weppack-dev-server for development. My project is running, but when i directly hitting the url with paramameters in browser then it gives me
GET http://localhost:8080/archives/index.js net::ERR_ABORTED otherwise i hit the same url with Link component then it is running
//main.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route, hashHistory} from 'react-router-dom';
import Archives from './modules/Archives';
import Layout from './modules/Layout';
import Featured from './modules/Featured';
import Settings from './modules/Settings';
import Home from './modules/Home';
console.log('hi');
ReactDOM.render((
<Router history={hashHistory}>
<div>
<Layout/>
<Route exact path={'/'} component={Home}/>
<Route path={'/featured'} component={Featured}/>
<Route path={'/archives/:id'} component={Archives}/>
<Route exact path={'/archives'} component={Archives}/>
<Route path={'/settings'} component={Settings}/>
</div>
</Router>
),document.getElementById('app'));
///////////////////////////////////////////////////////////////////////////
//Layout.js
import React from 'react';
import { Link } from 'react-router-dom';
import '../css/main.css';
const bstyle = {
color:'white',
background: 333333,
margin: '-9px',
};
export default class Layout extends React.Component{
render() {
return(
<div>
<h1>React Application</h1>
<ul>
<li><Link className='linktext' to='/'>Home</Link></li>
<li><Link className='linktext' to='/archives'>Archives</Link></li>
<li><Link className='linktext' to='/featured'>Featured</Link></li>
<li><Link className='linktext' to='/settings'>Settings</Link></li>
</ul>
{this.props.children}
</div>
)
}
}
I am getting the error cannot read property history but I defined it.
This used the work when I had it in main.jsx in my client folder but now it stops working.
The app file is in my imports folder.
import { Router, Route, Switch, Redirect } from "react-router-dom";
import createBrowserHistory from "history/createBrowserHistory";
const history = createBrowserHistory();
// App component - represents the whole app
export class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="container">
<Router history={history}>
<Switch>
<Route path="/" exact component={Home} />
<Route
path="/dashboard"
render={() =>
this.props.currentUser ? <Dashboard /> : <NoPermission />}
/>
<Route path="/test" component={Test} />
<Route component={NotFound} />
</Switch>
</Router>
</div>
);
}
}
more info:
import createBrowserHistory from "history/createBrowserHistory";
within that file createBrowserHistory is the default export.
export.default = createBrowserHistory;
When trying BrowserRouter instead of router and deleting the history const and props I get following error in my console.
modules.js:26944 Uncaught TypeError: Cannot read property 'history' of undefined
at Link.render (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:26944)
at modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:18399
at measureLifeCyclePerf (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:17679)
at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:18398)
at ReactCompositeComponentWrapper._renderValidatedComponent (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:18425)
at ReactCompositeComponentWrapper.performInitialMount (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:17965)
at ReactCompositeComponentWrapper.mountComponent (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:17861)
at Object.mountComponent (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:10622)
at ReactDOMComponent.mountChildren (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:16977)
at ReactDOMComponent._createInitialChildren (modules.js?hash=b38005f7c50b72cb1ea0945090b4ba307f31282f:14176)
When using BrowserRouter in my main.jsx I can get it working. I can change URL's but the new views do not render. So I think there still is something wrong with the history. In this case I have not defined it but I am not receiving any errors. Any way how I can check or fix this?
import React from "react";
import { Meteor } from "meteor/meteor";
import { render } from "react-dom";
import "../imports/startup/accounts-config.js";
import App from "../imports/layouts/App.jsx";
import Test from "../imports/Test.jsx";
import { BrowserRouter } from "react-router-dom";
Meteor.startup(() => {
render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("render-target")
);
});
Going further on Kyle's answer I added withrouter to my test component.
import React, { Component } from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router";
class Test extends Component {
static propTypes = {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
};
render() {
const { match, location, history } = this.props;
return (
<div>
<p>This is a test</p>
<p>
You are now at {location.pathname}
</p>
</div>
);
}
}
export default withRouter(Test);
I am using NavLinks to link to this route in my navigation bar component.
<NavLink to="/test" activeClassName="active">
Test
</NavLink>
However clicking those links does not render the test page. (the address in the URL bar does change). When I press refresh in the browser the page loads and the location.pathname shows the proper location.
If I remove the withrouter the functionality is the same.
I got it working by not using a component to nest the router in.
If somebody can explain me why I would greatly appreciate it.
import Navbar from "../components/Navbar.jsx";
import AccountsUIWrapper from "../components/AccountsUIWrapper.jsx";
//import pages
import Home from "../pages/Home.jsx";
import Dashboard from "../pages/Dashboard.jsx";
import Test from "../Test.jsx";
import NotFound from "../pages/NotFound.jsx";
import NoPermission from "../pages/NoPermission.jsx";
let currentUser = Meteor.user();
const App = () =>
<Router>
<div>
<Navbar currentUser={currentUser} />
<AccountsUIWrapper />
<p>
{currentUser ? currentUser._id : "current user id not found"}
</p>
<Switch>
<Route exact path="/" component={Home} />
<Route
path="/dashboard"
render={() => (currentUser ? <Dashboard /> : <NoPermission />)}
/>
<Route path="/test" component={Test} />
<Route component={NotFound} />
</Switch>
</div>
</Router>;
export default App;
React Router 4 has history baked into it. You can see from the documentation for BrowserRouter, HashRouter, and MemoryRouter that there is no argument for history.
If you would like to access history in React Router v4 you should use the withRouter HoC on the component that you wish to have access to it in. withRouter will make ({match, history, location }) available inside any component that it wraps.
As you can see from this line of code: var _createBrowserHistory = require('history/createBrowserHistory'); which is line 13 in BrowserRouter.js and HashRouter.js history is already included for you. It is also included in the memory router on line 9 of MemoryRouter.js.
Try changing your import at the top to import { BrowserRouter as Router, Route, Switch, Redirect } from "react-router-dom"; and then remove history={ history } from <Router />.
EDIT: Please take a look at the documentation for React Router 4. Here is a basic example.
Here is a post of the code incase the link ever goes dead.
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
const BasicExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/topics">Topics</Link></li>
</ul>
<hr/>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/topics" component={Topics}/>
</div>
</Router>
)
const Home = () => (
<div>
<h2>Home</h2>
</div>
)
const About = () => (
<div>
<h2>About</h2>
</div>
)
const Topics = ({ match }) => (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${match.url}/rendering`}>
Rendering with React
</Link>
</li>
<li>
<Link to={`${match.url}/components`}>
Components
</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
Props v. State
</Link>
</li>
</ul>
<Route path={`${match.url}/:topicId`} component={Topic}/>
<Route exact path={match.url} render={() => (
<h3>Please select a topic.</h3>
)}/>
</div>
)
const Topic = ({ match }) => (
<div>
<h3>{match.params.topicId}</h3>
</div>
)
export default BasicExample
I'm new to ReactJS and i am developing single page app and I'm just trying to import my components to main component but while clicking on route link it showing blank state or null.
src\components\Detail.js
import React from 'react';
import ReactDOM from 'react-dom';
class Detail extends React.Component {
render() {
return (
<div className="App">
<div className="App-header">
<h2>Detail</h2>
</div>
<p>This is the Detail page.</p>;
</div>
);
}
}
export default Detail;
Above module trying to import in App.js for routing
App.js
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
import { Detail } from './components/Detail.js'
const BasicExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/detail">Detail</Link></li>
<li><Link to="/topics">Topics</Link></li>
</ul>
<hr/>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/detail" component={Detail}/>
<Route path="/topics" component={Topics}/>
</div>
</Router>
)
I've not got any errors.
You need to import the other components too when you specify a route configuration and Detail is a default export so you should import without curly braces
import Home from './components/Home.js'
import About from './components/About.js'
import Detail from './components/Detail.js'
import Topics from './components/Topics.js'
Refer this answer for more info on named and Default export