history object with central Routes file - reactjs

I have seen many examples over the net on how to use history object with React Router. However, I havent stumbled upon a case where the example shows a central routes file as shown below:
routes.js
const RouteList = () => (
<main>
<Switch>
<Route path="/" exact component={HomePage} />
<Route component={Error} />
</Switch>
</main>
);
export default RouteList;
App.js
render() {
return (
<div>
<Header />
<RouteList />
<Footer />
</div>
);
}
history.js
import { createBrowserHistory } from 'history';
export default createBrowserHistory();
Can someone shed some light how i can use history with my centralized routes? Or if there is another similar thread please let me know thank you so much.

The custom history object need to be provided as a prop to the Router Provider component. In your case you can Specify a Router Provider in App.js or RouteList depending on whether Header and Footer also need Router props or not.
import browserHistory from './history.js';
...
render() {
return (
<Router history={browserHistory}>
<div>
<Header />
<RouteList />
<Footer />
</div>
</Router>
);
}
Also in your history.js file, import createBrowserHistory like
import createBrowserHistory from 'history/createBrowserHistory';

Related

ReactJS: 404 error on reloading the inner components in dev env

I am getting 404 error every time I am reloading any inner component. I always have to navigate to home page and then reload/refresh the page for the application to work again.
I have tried using the BrowserRouter but that didn't work either.
Here is my code:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import createBrowserHistory from 'history/createBrowserHistory';
import { Router, Route, Switch } from "react-router-dom";
const history = createBrowserHistory();
/** elements */
import Header from './components/elements/Header';
import Footer from './components/elements/Footer';
/** components */
import Projects from './components/Projects';
import ProjectsAdd from './components/ProjectsAdd';
import Categories from './components/Categories';
import CategoriesAdd from './components/CategoriesAdd';
export default class Index extends Component
{
render()
{
return (
<Router history={history}>
<div id="main">
<Header />
<section className="content">
<section id="pageRight">
<Switch>
<Route exact path={"/"} component={Projects} />
<Route path={"/projects/add"} component={ProjectsAdd} />
<Route exact path={"/categories"} component={Categories} />
<Route path={"/categories/add"} component={CategoriesAdd} />
</Switch>
</section>
</section>
<Footer />
</div>
</Router>
);
}
}
if (document.getElementById('layout'))
ReactDOM.render(<Index />, document.getElementById('layout'));
I found the solution (https://youtu.be/vNof0z32l84).
I hope this may come in handy for someone. However, If you feel there is a room for improvement then please let me know. :)

react router 4 switch showing two components

I'm trying to split my routes into many files, to achieve this I have a central file called routes.
import React from "react";
import { Router, Route, Switch } from "react-router-dom";
import history from "./History";
import StreamRoutes from "./stream/StreamRoutes";
const Routes = props => {
return (
<React.Fragment>
<Router history={history}>
<Switch>
<Route path="/" exact component={props => <h1>hello world</h1>} />
<StreamRoutes />
</Switch>
</Router>
</React.Fragment>
);
};
export default Routes;
and then a route file for all the main component like so:
import React from "react";
import { Route } from "react-router-dom";
import StreamCreate from "./components/StreamCreate";
import StreamEdit from "./components/StreamEdit";
import StreamList from "./components/StreamList";
import StreamShow from "./components/StreamShow";
const StreamRoutes = props => {
return (
<React.Fragment>
<Route path="/streams" exact component={StreamList} />
<Route path="/streams/new" exact component={StreamCreate} />
<Route path="/streams/:id" exact component={StreamShow} />
<Route path="/streams/edit/:id" exact component={StreamEdit} />
</React.Fragment>
);
};
export default StreamRoutes;
this works except when I try to access "/streams/new" or "/streams/:id", in any of those cases the router show both components at once.
I would like to know how to fix this or a better way to organize my routes would be highly appreciated.
It is possible to use a regex like FuzzyTree suggest, but this can get messy in a bigger project. I would suggest replacing React.Fragment in your StreamRoutes with Switch. This way it works like you'd expect.

ReactJS: Check the render method of `MainRouter`. Error

I'm trying to export two named modules from one component file and somehow keep getting the "Check the render method..." error.
Here's a look at my code.
App.jsx
import React from 'react';
import { MainRouter } from '../Router';
const App = () => (
<div className="card">
<MainRouter />
</div>
);
export default App;
Router.jsx - which is what's being imported above
import React, { Fragment } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import PrivateRoute from './components/PrivateRoute';
import Header from './components/Header';
import AdminNav from './components/AdminNav';
import Calendar from './pages/Calendar';
import Search from './pages/Search';
import AdminLogin from './pages/AdminLogin';
import Admin from './pages/Admin';
import New from './pages/Admin/New';
import Users from './pages/Admin/Users';
let styles = {};
styles.body__wrapper = {
padding: '2%'
};
export const MainRouter = () => (
<Router>
<Fragment>
<div className="nav__wrapper">
<Header />
</div>
<div style={styles.body__wrapper}>
<Switch>
<Route exact path="/" component={Calendar} />
<Route path="/search/:name" component={Search} />
<Route path="/admin/signin" component={AdminLogin} />
<PrivateRoute path="/admin" component={Admin} />
</Switch>sasd
</div>
</Fragment>
</Router>
);
export const AdminRouter = (props) => (
<div className="container">
<Router>
<Fragment>
<AdminNav {...props}/>
<div className="my-3">
<Switch>
<Route path="/users" component={Users} />
<Route path="/new" component={New} />
</Switch>
</div>
</Fragment>
</Router>
</div>
);
I've tried doing export { MainRouter, AdminRouter } but doesn't seem to work as well.
Complete error message:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of `MainRouter`.
I actually figured it out.
I was using several index.js on every route component and incorrectly configured the exports on almost all of them, causing the whole app to crash.

React Link doesn't trigger the router changement

In my react app I've tried lot of different router, route, and solution find on internet.
The fact is i'm using <HashRouter> from react-router-dom and redux in my app.
When I change the url in my browser the right route is triggered and the right component is loaded.
The issue :
When i click on <Link> component the url change, the history props on the router change but nothing happenned in the app...
Here are my app architecture and code :
MainApp.jsx
render(){
<Provider store={store}>
<HashRouter>
<div className="main-app">
<StickyContainer>
<Header toggleHelp={() => this.toggleOverlay()} />
<Sticky>
<Toolbar /> //Here are my <Link/>
</Sticky>
<App/>
<Footer />
</StickyContainer>
</div>
</HashRouter>
</Provider>
}
App.js
import React from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as Actions from 'Actions';
import Main from 'Components/Main/Main';
import {withRouter} from 'react-router-dom';
const App = ({elements, actions,documents,filters}) => (
<div>
<Main elements={elements} actions={actions} documents={documents} filters={filters} />
</div>
)
const mapStateToProps = state => ({
elements: state.elements,
documents: state.documents,
filters:state.filters
});
const mapDispatchToProps = dispatch => ({
actions: bindActionCreators(Actions, dispatch)
});
export default withRouter(connect(
mapStateToProps,
mapDispatchToProps
)(App));
And finally my Main.jsx
render(){
<div className="main-authenticated">
<Switch>
<Route path="/home" component={Home} />
<Route path="/reporting" component={Reporting} />
<Route path="/about" component={About} />
<Route path="/disconnect" component={ErrorPage} />
</Switch>
</div>
}
I already tried with a BrowserRouter, a basic Router with history but always this issue. Don't know if it's due to my project architecture or something else.
UPDATE
Moved withRouter on Main.jsx and got the same issue.
Main.jsx
render(){
<div className="main-authenticated">
<Switch>
<Route path="/home" component={Home} />
<Route path="/reporting" component={Reporting} />
<Route path="/about" component={About} />
<Route path="/disconnect" component={ErrorPage} />
</Switch>
</div>
}
export default withRouter(Main)
As #ShubhamKhatri said, I needed to export my Main component with withRouter function from react-router.
But there was an other issue, the Link included in the Toolbar component was not triggered the router due to the Sticky Component from react-sticky.
Remove the Sticky component wrapper on the MainApp correct the problem.
Final solution :
exporting Main.jsx
class Main
[...]
export default withRouter(Main);
MainApp.jsx
<Provider store={store}>
<HashRouter>
<div className="main-app">
<Header />
<Toolbar/>
<App>
<Footer />
</div>
</HashRouter>
</Provider>

React-Router & MobX - Provider

I am trying to access my store from every component page I have, so I followed the following tutorial in order to connect React Router & MobX.
http://frontendinsights.com/connect-mobx-react-router/
However, I am facing a problem at The MobX way – Provider component.
This is the code exmaple:
import { Provider } from 'mobx-react';
import usersStore from './stores/usersStore';
import itemsStore from './stores/itemsStore';
const stores = { usersStore, itemsStore };
ReactDOM.render(
<Provider {...stores}>
<Router history={history}>
<Route path="/" component={App}>
</Route>
</Router>
</Provider>,
document.getElementById('app')
);
I tried to do the same in index.js
import React from 'react'
import { render } from 'react-dom'
import { Router, hashHistory, Route, IndexRedirect } from 'react-router'
import App from './webapp/App'
import Home from './components/pages/Home'
import Dogs from './components/pages/Dogs'
import Cats from './components/pages/Cats'
import Provider from 'mobx-react'
import RootStore from './webapp/stores'
const store = RootStore
render((
<Provider rootStore={store}>
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRedirect to="/home" />
<Route path="/home" component={Home}/>
<Route path="/dogs" component={Dogs}/>
<Route path="/cats" component={Cats}/>
</Route>
</Router>
</Provider>
), document.getElementById('app'))
However, because of <Provider/>, I am getting an error:
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).
Why am I getting that? It should work doesn't it?
Thanks for any help !
If it's a web app, react-router-dom should be used.
Here is the correct way to inject store with Provider https://github.com/mobxjs/mobx-react#observer
I wrote a solution for your code without using decorator, so it supports create-react-app:
import React, { Component } from 'react';
import { Provider, Observer } from 'mobx-react';
import { observable } from 'mobx';
import { BrowserRouter, Switch, Route, Link, Redirect } from 'react-router-dom';
const myStore = observable({
home: 'Home',
cat: 'Cat',
});
const Home = () => (
<Observer
inject={stores => ({ myStore : stores.myStore })}
render={props => (<section><h1>{props.myStore.home}</h1></section>)}
/>
);
const Cat = () => (
<Observer
inject={stores => ({ myStore : stores.myStore })}
render={props => (<section><h1>{props.myStore.cat}</h1></section>)}
/>
);
class App extends Component {
render() {
return (
<BrowserRouter>
<Provider myStore={myStore}>
<div className="App">
<header className="App-header">
<nav>
<ul>
<li><Link to="/home">HOME</Link></li>
<li><Link to="/cat">CAT</Link></li>
</ul>
</nav>
</header>
<Switch>
<Route path='/home' exact component={Home} />
<Route path='/cat' exact component={Cat} />
<Redirect from="/" to="/home" />
</Switch>
</div>
</Provider>
</BrowserRouter>
);
}
}
export default App;
All the components are in App.js file. There is no change in default index.js from create-react-app.
Note:
The another way to doing this, it's to simply create a singleton class for the store and use export default new Store() to make it available to all components. The class itself doesn't have to be observable, but its properties do.

Resources