react-router link for route from another component - javascript

I have a React Component called ContentBar that holds a Route to display dynamic content:
//ContentBar.js
var React = require('react')
import ContentBarRoute from '../../../../routes/contentbar.routes'
const ContentBar = () =>
(
<ContentBarRoute />
)
export default ContentBar
I've placed this ContentBar in my root App structure:
//App.js
<div className="logBar">
<ErrorBoundary>
<Responsive minWidth={960}>
<ContentBar />
</Responsive>
</ErrorBoundary>
</div>
And I've created a route for a new menu in the ContentBarRoute component which I'm loading in the ContentBar:
//ContactBarRoute.react.js
const ContentBarRoute = () => (
<main>
<Switch>
<Route exact path="/logbar"component={LogBar}/>
<Route path="/user/:number/settings" />
<Route path="/user/:number/profile" />
<Route path="/user/add" component={UserAddMenu} />
</Switch>
</main>
)
When I try to link to /user/add from another component though, I'm not able to update the route from another component:
//Contactlist.react.js
<div className="contact-list useradd">
<Button as={Link} to="/user/add" className="btn-useradd">
<FontAwesome className="icon-adduser" tag="i" name="plus" />
</Button>
</div>
Can someone help me see what I'm doing wrong here? There's not a lot of information about routing between components, I found one answer in my research but it was slightly different: React-Router-4 routing from another component
The problem is that my routes and links are in separate areas of the hierarchy, whereas that guy's components were all close together.
Update:
The other example doesn't talk about rendering new components in place of old ones where one component is totally separate from the other:
Here is my router definition it exists in the class that sends the App to the html div:
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
//import { createStore } from 'redux'
import { HashRouter } from 'react-router-dom'
import configureStore from '../tools/store.enhancer';
import App from '../javascripts/entry';
//import rootReducer from '../app/reducers/index'
//let store = createStore(rootReducer)
const store = configureStore();
render((
<Provider store={store}>
<HashRouter>
<App />
</HashRouter>
</Provider>
), document.getElementById('root'));
The behavior I expect is that the existing component is switched out for the user-add component, but the actual behavior is that nothing happens when I click the button, and I get an error saying
Hash history cannot PUSH the same path; a new entry will not be added to the history stack

Related

React app routing doesn't load content unless page reloaded

I've been working on a react single page app and have been trying to get the routing to work.
I believe the routing itself actually works however the page does not load the correct content unless the page is manually reloaded. Back and forward browser arrows also work.
For example I can navigate to localhost:3000 fine and the content is loaded correctly but when I press a button to navigate to localhost:3000/contacts nothing is displayed unless I refresh the page. Once manually refreshed the contacts page shows up. What gives?
index.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter as Router } from 'react-router-dom';
// Import App component
import App from './App'
// Import service workers
import * as serviceWorker from './serviceWorker'
// Render App component in the DOM
ReactDOM.render(
<Router>
<App />
</Router>
, document.getElementById('root')
)
serviceWorker.unregister()
App.tsx
// Import necessary dependencies
import React from 'react'
import Routes from './Routes'
// Create App component
function App() {
return (
<div className="App">
<Routes />
</div>
)
}
export default App
history.tsx
import { createBrowserHistory as history} from 'history';
export default history();
Home/Home.tsx
import React, { Component } from "react";
import history from './../history';
import "./Home.css";
export default class Home extends Component {
render() {
return (
<div className="Home">
hello home
<button onClick={() => history.push('/Contact')} value='click here'>Get Started</button>
</div>
);
}
}
Contact/Contact.tsx
import React, { Component } from 'react';
class Contact extends Component {
render() {
return (
<div>
hello world
</div>
);
}
}
export default Contact;
Routes.tsx
import React, { Component } from "react";
import {BrowserRouter, Router, Switch, Route } from "react-router-dom";
import Contact from "./Contact/Contact";
import Home from "./Home/Home"
import history from './history'
export default class Routes extends Component {
render() {
return (
<div>
<Router history={history}>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/Contact" component={Contact} />
</Switch>
</Router>
</div>
)
}
}
Any help greatly appreciated
I think there's some extra code that might be causing conflict. You're defining the Router from react-router-dom twice:
Once here, in index.tsx
ReactDOM.render(
<Router> // here
<App />
</Router>
, document.getElementById('root')
)
and then again in Routes.tsx
<Router history={history}> // here
<Switch>
<Route path="/" exact component={Home} />
<Route path="/Contact" component={Contact} />
</Switch>
</Router>
You have to drop one of them, they're probably conflicting each other
Update
In addition to that, I think you should not use the history object directly from your export, but access it through the HOC withRouter. Then, you'd wrap
So you'd do something like this
import React, { Component } from "react";
import { withRouter } from 'react-router-dom'
import "./Home.css";
class Home extends Component {
const { history } = this.props
render() {
return (
<div className="Home">
hello home
<button onClick={() => history.push('/Contact')} value='click here'>Get Started</button>
</div>
);
}
}
export default withRouter(Home)
I think the issue here is that you need to wrap your pages with withRouter() like so:
import React, { Component } from "react";
import history from './../history';
import "./Home.css";
import { withRouter } from 'react-router-dom'; //<---------- add this
class Home extends Component {
render() {
return (
<div className="Home">
hello home
<button onClick={() => history.push('/Contact')} value='click here'>Get Started</button>
</div>
);
}
}
default export withRouter(Home); //<-------------- and add this
You will need to do the same on your Contact page as well.
Why do you have two routers?
I guess you simply need to remove the Router either in index.tsx or in Routes.tsx
According to you file naming I would remove the Router in Routes.tsx
It seems like you are using the history package for navigation. If you are using the react-router v5, then you may have to downgrade the history package to 4.10.1 until the history package developers issue a new release with the fix. As of writing this, the latest release version of history package is v5.0.1, and if you see a new release than this, you can try with that version first to see if it works, before doing the downgrade to 4.10.1
Issue Link -> https://github.com/remix-run/history/issues/804

How to make material ui sidebar to open the main content in react?

I am a newbie to react and currently developing an application,
BACKGROUND
It has admin, faculty, student, dashboards.amd a static landing page with buttons to go to /admin/login ,/faculty/login ,/student/login. which opens respective dashboards [![Once admin logins he gets this dashboard page ][1]][1]
PROBLEM:
App.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import Routes from "./routes";
import firebase from "./Firebase";
const App = props => {
return (
<BrowserRouter>
<Routes {...props} />
</BrowserRouter>
);
};
firebase.auth().onAuthStateChanged(user => {
ReactDOM.render(<App user={user} />, document.getElementById("root"));
});
Routes.js
import React from "react";
import { Switch, Route, BrowserRouter } from "react-router-dom";
import MainLayout from "./OtherComponents/Common/MainLayout";
//Home
import Home from "./MainComponents/Home";
import HomePublicRoute from "./OtherComponents/Routes/Home/HomePublicRoute";
//ADMIN
//components
import AdminLogin from "./OtherComponents/Login/Admin";
import AdminDash from "./MainComponents/Admin";
import AdminPublicRoute from "./OtherComponents/Routes/Admin/AdminPublicRoutes";
import AdminPrivateRoute fro"./OtherComponents/Routes/Admin/AdminPrivateRoutes";
//pages
import PageDashboard from "./MainComponents/Admin/pages/dashboard";
import AdminTaluka from "./MainComponents/Admin/pages/taluka";
const Routes = props => {
console.log(props);
return (
<MainLayout>
<Switch>
<AdminPublicRoute
{...props}
exact
restricted={true}
path="/admin/login"
component={AdminLogin}
/>
<AdminPrivateRoute
{...props}
path="/admin/admindashboard"
exact
component={AdminDash}
/>
<AdminPrivateRoute
{...props}
path="/admin/pagedashboard"
exact
component={PageDashboard}
/>
<AdminPrivateRoute
{...props}
path="/admin/taluka"
exact
component={AdminTaluka}
/>
<HomePublicRoute path="/" component={Home} />
</Switch>
</MainLayout>
);
};
export default Routes;
MainLayout.js
import React from "react";
//var reactRouterToArray = require("react-router-to-array");
const MainLayout = props => {
//console.log(reactRouterToArray(props.children));
return <div>{props.children}</div>;
};
export default MainLayout;
Sidebar doesn't open the content inside the main container instead it opens in a new tab if i use route inside routes.js .
Sidebar doesn't open the content if i use route inside AdminDash.js .
i have tried passing the routes using props (props.children) to AdminDash( its not receivng the prop)
I am using private and public routes.
I am confused and I don't know where am I going wrong any suggetions , or hints would be helpful.
Thanks in advance.
Sidebar doesn't open the content inside the main container instead it opens in a new tab if i use route inside routes.js .
Inside LeftDrawer you are rendering links to the content. You should use react-router-dom Link elements.
Like this:
import { Link } from 'react-router-dom'
<Link to="/about">About</Link>
Sidebar doesn't open the content if i use route inside AdminDash.js .
Routes shouldn't be defined multiple times. You have defined /admin/pagedashboard both in AdminDash.js and Routes.js. If you want to have a shared shell around the content, define routes inside the shell component and remove exact route from the parent routes.
Example:
MainLayout
.Routes
../admin
...AdminDash (Shell for multiple pages, admin layout)
..../admindashboard
.....AdminDasboard
..../pagedashboard
.....PageDashboard
i have tried passing the routes using props (props.children) to AdminDash( its not receivng the prop)
You should just import them when needed.
EDIT:
Remove exact from the Routes.js <Route path='/admin' component={AdminDash} /> and in AdminDash try
const AdminDash = ({ match }) => (
<div>
<Route path={${match.url}/admindashboard} component={AdminContent}/>
<Route path={${match.url}/pagedashboard} component={PageContent}/>
</div>
);
In the above example take note to change AdminContent and PageContent with the names of your components.

React-Router-Dom | URL Changes, but the component doesn't update

I have a list of items, in a table in React. When I click on the table Link, the url updates, but the component doesn't get rendered. If I refresh the component is there.
I have read that some React-router-dom versions have some problems, and there are a lot of solutions that are being discussed here:
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md
That although is for the Beta Versions. I assume I need to do something with the higher order function withRouter from react-router-dom, but it doesn't work for me. On top of that, withRouter has been set up globally in the App.
const AppHeader = withRouter(({ history, location, ...props }) => (
<Header {...props} currentRoute={location.pathname} />
));
The thing is, my App has several applications. One Angular and 2 React ones. Do I need to set it up, on each application as well? This is the Parent Component with the router for the application the Links aren't working.
import React from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import 'react-tagsinput/react-tagsinput.css';
import PolicyRoutes from 'dataprotection/policies/containers/PolicyRoutes';
import './styles.scss';
const AppRouter = () => (
<Switch>
<Route exact path="/policies" component={PolicyRoutes} />
<Redirect to="/policies" />
</Switch>
);
AppRouter.propTypes = {};
function mapStateToProps() {
return {};
}
export default connect(mapStateToProps)(AppRouter);
I have tried 2 solutions. The first is to actually wrap my component withRouter like so:
<Route exact path="/policies" component={withRouter(PolicyRoutes)} />
And the second is to wrap withRouter, the connect function. Both aren't working.
This is the component not working:
import React from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import PropTypes from 'prop-types';
import OverviewScreen from '../OverviewScreen';
import PolicyDetailsScreen from '../PolicyDetailsScreen';
const PolicyRoutes = ({ match }) => (
<Switch>
<Route exact path={`${match.url}/details/:policyId`} component={PolicyDetailsScreen} />
<Route exact path={match.url} component={OverviewScreen} />
<Redirect to={match.url} />
</Switch>
);
PolicyRoutes.propTypes = {
match: PropTypes.object
};
export default PolicyRoutes;
Can anyone help? I don't know what the problem is...

Content in between Header/Footer

I'm building a site where each page has a <TopNav>, <Footer> and a <Subfooter>.
As I understand it, the entry point of the app, should include these three components, and an additional component/s should render depending on the route the user is on.
I've built my entry point like so:
App.js
const App = () => (
<div>
<TopNav />
<Footer />
<Subfooter />
</div>
)
index.js
ReactDOM.render(
<App />,
document.getElementById('root')
);
The problem with the way I've structured this is that I can't render anything in between <TopNav> & <Footer>. Should I do something like this in App.js and somehow inject the proper components into <PageContent> based on the route?
App.js
const App = () => (
<div>
<TopNav />
<PageContent />
<Footer />
<Subfooter />
</div>
)
Also, all each component in app requires a router as they all contain <nav> - where should I be defining the <Router> for all three of these components?
What is the correct approach to adding any necessary component between the three listed in App.js - and where should the routing code go to dictate the behavior for all three of these components?
One way of doing this could be:-
Routes.js
import React,{ Component } from 'react';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
import App from './components/app';
import SomeComponent from './components/some-component';
import AnotherComponent from './components/another-component';
const taskRouter = (
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={SomeComponent} />
<Route path="/another" component={AnotherComponent} />
</Route>
</Router>
);
export default taskRouter;
Main.js
import React from 'react';
import ReactDOM from 'react-dom';
import Router from './Routes';
ReactDOM.render(<Router/>, document.getElementById('root'));
Finally inside App.js
const App = (props) => (
<div>
<TopNav />
{props.children}
<Footer />
<Subfooter />
</div>
)
All route components will render themselves inside props.children.
Hope that helps.

react router 4 nested components not working properly

I am switching from react-router 3.x to 4.x and I am not able to render nested routes.
I bootstrapped an application using create-react-app
index.js file
import React from 'react';
import ReactDOM from 'react-dom';
import Routes from './routes';
import './index.css';
ReactDOM.render(<Routes />, document.getElementById('root'));
routes.js file
import React from 'react';
import _ from 'lodash';
import {
BrowserRouter as Router,
Route,
} from 'react-router-dom';
import { dojoRequire } from 'esri-loader';
import EsriLoader from 'esri-loader-react';
import App from './components/App';
import Home from './components/Home';
/**
* Helper component to wrap app
*/
class AppWrapper extends React.Component {
/**
* Util function to render the children
* Whenever a state change happens in react application, react will render the component again
* and we wish to pass the updated state to the children as props
*/
renderChildren() {
const {children} = this.props;
if (!children) {
return;
}
return React.Children.map(children, c => React.cloneElement(c, _.omit(this.props, 'children'), { }));
}
render() {
const child = this.renderChildren();
return (
<App {...this.props}>
{child}
</App>
);
}
}
/**
* Root Loader component to load esri api
*/
class LoaderComponent extends React.Component {
constructor(props) {
super(props);
this.state = { loaded: false };
}
/**
* Callback fired when arc GIS api is loaded
* Now load the requirejs modules using dojorequire
*/
esriReady() {
dojoRequire(['esri/Map', 'esri/views/MapView'], (Map, MapView) => {
this.setState({ Map, MapView, loaded: true });
});
}
render() {
const options = {
url: 'https://js.arcgis.com/4.3/',
};
return (
<div>
<EsriLoader options={options} ready={this.esriReady.bind(this)} />
<AppWrapper {...this.state}>
<Route exact path="/home" component={Home} />
</AppWrapper>
</div>
);
}
};
const Routes = (props) => (
<Router {...props}>
<Route exact path="/" component={LoaderComponent} />
</Router>
);
export default Routes;
App and home components are simple div tags that renders <div>Hello world App</div> and <div>Hello world Home</div>
The App component renders perfectly, but when I navigate to http://localhost:3000/home component I see an empty page.
What I would like to do is
When the user launched the app the user should be redirected to /home and I would like to define two additional routes for App Component
<Route exact path="/a" component={A} />
<Route exact path="/b" component={B} />
Currently I am not able to redirect to /home on app load and not able to define nested routes for App Component.
NOTE: This above code was working fine for react-router version 3.x. To redirect on page load I would use IndexRedirect.
I already had a look at this and this question and I tried all possible solutions in those questions but none is working.
I would like to have all the route handling in routes.js file.
You could achieve such routing with Switch and Redirect:
import React from 'react';
import {Route, Switch, Redirect} from 'react-router-dom';
import {LoaderComponent, AppWrapper , Home, A, B} from './mycomponents';
const routes = (
<LoaderComponent>
<AppWrapper>
<Switch>
<Route exact path='/' render={() => <Redirect to='/home' />} />
<Route exact path='/home' component={Home} />
<Route exact path='/a' component={A} />
<Route exact path='/b' component={B} />
</Switch>
</AppWrapper>
</LoaderComponent>
);
export default routes;
And use the routes.js file something like this:
import React from 'react';
import {render} from 'react-dom';
import {Router} from 'react-router-dom';
import createHistory from 'history/createBrowserHistory';
import routes from './routes';
const history = createHistory();
const App = () =>
<Router history={history}>
{routes}
</Router>;
render(<App />, document.getElementById('root'));
Hey I have implemented react-router-v4, for a simple sample project. here is the github link : How to Implement the react-router-v4. please go through it. very simple.
to run : clone it and hit npm install. hope this will help to you.

Categories