React-router renders component when I update the browser - reactjs

I am working with react-router and react-md. My problem is that when I change url through links the components not renders. If I press F5 works. My code is this:
Verions
"react-router": "^5.0.0",
"react-router-dom": "^5.0.0"
App.js
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {
sidebarVisible: false
};
}
render() {
const { sidebarVisible } = this.state;
return (
<div>
<Header showDrawer={this.showDrawer} />
<Sidebar handleVisibility={this.handleVisibility} closeDrawer={this.closeDrawer} sidebarVisible={sidebarVisible} />
<Content />
</div>
);
}
}
export default App;
index.js
import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
WebFontLoader.load({
google: {
families: ['Roboto:300,400,500,700', 'Material Icons'],
},
});
render(
<Router>
<App />
</Router>
, document.getElementById('root'));
serviceWorker.unregister();
content.js
import React, { Component } from 'react'
import PropTypes from 'prop-types';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
class Content extends Component {
render() {
const { title } = this.props;
return (
<Router>
<div>
<Route exact path="/client" component={Client} />
<Route path="/payment" component={Payment} />
<Route path="/invoice" component={Invoice} />
</div>
</Router>
);
}
}
export default Content
NavItemLink.js
import React from 'react';
import { Link, Route } from 'react-router-dom';
const NavItemLink = ({ label, to, icon, exact }) => (
<Route path={to} exact={exact}>
{({ match }) => {
let leftIcon;
if (icon) {
leftIcon = <FontIcon>{icon}</FontIcon>;
}
return (
<ListItem
component={Link}
active={!!match}
to={to}
primaryText={label}
leftIcon={leftIcon}
/>
);
}}
</Route>
);
export default NavItemLink;
I think that in the content.js, react-router must detect the change and to renders the components.

Related

I am haveing problem when i am try to change my class component in functional component in react js

app.js file code i want to convert it
import Toolbar from "./components/Toolbar";
// import Iqac from "./components/Iqac/iqac";
import React from "react";
import "./styles.css";
import SideDrawer from "./components/sidemenu/SideDrawer";
import BackDrop from "./components/backdrop/BackDrop";
import { Route, Router, Routes } from "react-router-dom";
class App extends React.Component {
state = {
};
drawerToggleClickHandler = () => {
this.setState(prevState => {
return { sideDrawerOpen: !prevState.sideDrawerOpen };
});
};
backDropClickHandler = () => {
this.setState({ sideDrawerOpen: false });
};
render() {
// let sideDrawer;
let backdrop;
if (this.state.sideDrawerOpen) {
// sideDrawer = <SideDrawer />;
backdrop = <BackDrop click={this.backDropClickHandler} />;
}
return (<>
<div className="tool">
<Toolbar drawerToggleClickHandler={this.drawerToggleClickHandler} />
<SideDrawer show={this.state.sideDrawerOpen} />
{backdrop}
</div>
</>
);
}
}
export default App;
i have tried to change also i want to impliment react router dom v6 so that is why is need to do this and i don't know how to do in react-class based component
import Toolbar from './components/Toolbar'
import Footer from './components/Footer'
import Home from './Pages/Home'
import { useState } from "react";
import About from "./Pages/About"
import {
BrowserRouter as Router,
Route,
Routes
} from "react-router-dom";
const App = () => {
const [state, setstate] = useState({
sideDrawerOpen: false
});
return (
<>
<Router>
<Toolbar />
<Routes>
<Route path='/' element={<Home />}> </Route>
<Route path='/about/*' element={<About />}> </Route>
</Routes>
</Router>
<Footer />
</>
);
}
export default App;
i want to use react router dom and i thing v6 does't work with class
component
please help me resolve this issue i need to lot of your support thankyou so much in advance for the help
Try to change your code like this:
import Toolbar from './components/Toolbar';
import Footer from './components/Footer';
import Home from './Pages/Home';
import { useState } from 'react';
import About from './Pages/About';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
const App = () => {
const [sideDrawerOpen, setSideDrawerOpen] = useState(false);
const drawerToggleClickHandler = () => {
setSideDrawerOpen((prevState) => !prevState);
};
const backDropClickHandler = () => {
setSideDrawerOpen(false);
};
return (
<div className='tool'>
<Toolbar drawerToggleClickHandler={drawerToggleClickHandler} />
<SideDrawer show={sideDrawerOpen} />
{sideDrawerOpen && <BackDrop click={backDropClickHandler} />}
<Router>
<Toolbar />
<Routes>
<Route path='/' element={<Home />}>
{' '}
</Route>
<Route path='/about/*' element={<About />}>
{' '}
</Route>
</Routes>
</Router>
<Footer />
</div>
);
};
export default App;

React Router props.history

I'm a new to React.js with asp.net core, and I got an error that I don't understand.
I created protected route like that :
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import auth from './auth.js'
export const ProtectedRoute = ({ component: Component, ...rest }) => {
return (
<Route
{...rest}
render = {props => {
if(auth.estAuthentifier()){
return <Component {...props}/>
} else {
return <Redirect to={
{
pathname: "/",
state: {
from: props.location
}
}
} />
}
}}
/>
);
}
In my App.js, I added the protected route like that :
import React, { Component } from 'react';
import { BrowserRouter, Switch, Route } from 'react-router';
import { Login } from './components/Login'
import { Layout } from './components/Layout';
import { Home } from './components/Home';
import { ProtectedRoute } from './components/protected.route';
export default class App extends Component {
static displayName = App.name;
render () {
return (
<div>
<Switch>
<Route exact path="/" component={Login} />
<Layout>
<ProtectedRoute exact path="/home" component={Home}/>
</Layout>
<Route path="*" component={() => "404 NOT FOUND"}/>
</Switch>
</div>
);
}
}
And, the Layout component render all components with my NavBar included :
import React, { Component } from 'react';
import { Container } from 'reactstrap';
import { NavMenu } from './NavMenu';
import '../css/Layout.css';
export class Layout extends Component {
static displayName = Layout.name;
render () {
return (
<div className="conteneur-principal">
<NavMenu />
<Container>
{this.props.children}
</Container>
</div>
);
}
}
The problem is the next : I put the logout button in my navigation bar component but when I'm trying to logout and redirect to Login, i got the following error : TypeError: Cannot read property 'push' of undefined
NavMenu.js :
import React, { Component } from 'react';
import { NavLink } from 'reactstrap';
import { Link } from 'react-router-dom';
import auth from './auth';
import { withRouter } from 'react-router-dom';
import '../css/SideBarNav.css';
export class NavMenu extends Component {
static displayName = NavMenu.name;
constructor(props) {
super(props);
console.log(this.props);
this.deconnexion = this.deconnexion.bind(this);
}
deconnexion = () => {
auth.logout(() => {
this.props.history.push('/'); //LINE IN ERROR
})
}
render () {
return (
<div className="conteneur-menu">
<img src="images/familieu-logo-clear.png" alt="logo-familieu" title="logo-familieu" className="is-clickable logo-familieu"/>
<div className="conteneur-link">
<NavLink tag={Link} className="menu-link" to="/">Home</NavLink>
</div>
<input type="button" value="Déconnexion" className="btn-deconnexion" onClick={this.deconnexion}/>
</div>
);
}
}
What should I do to make my logout button work ?
Thanks alot
In NavMenu.js you are importing the withRouter, but is not used.
Wrap the export of component with withRouter like this:
export default withRouter(NavMenu);

React-Router-Dom Link not working in a nested component. Update url parameters, but component doesn't load on click. Works if I refresh after click

I have a NavBar that's on multiple pages that allows me to search for an user. After the searching, clicking on it should re-direct me to the user page via Link from react-router-dom. The problem is this only works on the main page, and doesn't work when clicking from an user's page.
I've tried adding WithRouter to all my related components (containers, parents, and the children). Also tried fiddling with the Route pathing / exact pathing syntax to no avail.
*Removed components imports and non-relavant code for clarity.
/app.jsx
import React from 'react';
import { Provider } from 'react-redux';
import {
Route,
Redirect,
Switch,
Link,
HashRouter,
withRouter,
} from 'react-router-dom';
import { AuthRoute, ProtectedRoute } from '../utils/route_utils';
const App = () => (
<div className="main">
<HashRouter>
<Switch>
<AuthRoute exact path="/" component={LoginContainer} />
<AuthRoute exact path="/signup" component={SignupContainer} />
<ProtectedRoute exact path="/feed" component={FeedContainer} />
<ProtectedRoute exact path="/users/:userId" component={GreetingContainer} />
<ProtectedRoute exact path="/posts/:postId" component={PostShowContainer} />
<ProtectedRoute exact path="/upload" component={Upload} />
<ProtectedRoute exact path="/accounts/edit" component={AccountsEditContainer} />
<Route component={Errors} />
</Switch>
</HashRouter>
</div>
);
export default withRouter(App);
/greeting_container.jsx
import React from 'react';
import { withRouter } from 'react-router-dom';
const mapStateToProps = (state, ownProps) => {
...
};
const mapDispatchtoProps = (dispatch) => ({
....
});
export default withRouter(connect(mapStateToProps, mapDispatchtoProps)(Greeting));
/greeting.jsx
import React from 'react';
import { Link } from 'react-router-dom';
import NavBarContainer from '../nav_bar/nav_bar_container';
class Greeting extends React.Component {
constructor(props) {
super(props);
this.renderPosts = this.renderPosts.bind(this);
}
render() {
if (!this.props.user) return null;
const profileUser = parseInt(this.props.match.params.userId)
const user = this.props.user
return (
<div className="user-page-container">
<Modal currentUser={user} />
<NavBarContainer />
</div>
}
export default Greeting;
/nav_bar_container.jsx
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import NavBar from './nav_bar';
const mapStateToProps = (state) => {
....
};
const mapDispatchToProps = (dispatch) => ({
...
});
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(NavBar));
/nav_bar.jsx
import React from 'react';
import { Link, withRouter } from 'react-router-dom';
import NavBarSearch from './nav_bar_search';
const NavBar = (props) => {
return (
<div>
< NavBarSearch
fetchSearchedUsers={props.fetchSearchedUsers}
searchResults={props.searchResults}
/>
</div>
);
};
export default withRouter(NavBar);
/nav_bar_search.jsx
import React from 'react';
import NavBarSearchResults from './nav_bar_search_results';
import { withRouter } from 'react-router-dom';
class NavBarSearch extends React.Component {
constructor(props) {
super(props);
this.state = {
searchInput: ''
}
this.generateSearch = this.generateSearch.bind(this)
}
render() {
return (
<div >
<input className="search-bar-test" onChange={this.generateSearch} type="text" placeholder='Search' />
{this.state.searchInput ? <NavBarSearchResults
searchResults={this.props.searchResults}
handleClick={this.handleClick}
// key={this.props.searchResults.id}
/> : null
}
</div>
)
}
}
export default withRouter(NavBarSearch);
/nav_bar_search_results.jsx
import React from 'react';
import { withRouter, Link } from 'react-router-dom';
const NavBarSearchResults = function({ searchResults, handleClick }) {
let results = searchResults ? Object.entries(searchResults).map((result) =>
<Link className="search-links" to={`/users/${result[0]}`} onClick={e => handleClick} key={result[0]}>
<div className="search-results-item">
<img className="search-results-image" src={result[1].photoUrl} />
{result[1].username}
</div>
</Link>
) : null
return (
<div className="search-results-container">
{results}
</div>
);
}
export default withRouter(NavBarSearchResults);
Once again, it is the Link in the Nav_Bar_Search_Results.jsx file that is not working. This file is nested several levels deep starting from the Greeting.jsx file. The string interpolation I'm doing is the user_id number. Please recall that the url parameters updates and the page works if I CLICK and REFRESH page, but not on first click alone.
The correct user page should render as specified by the url parameters

react-router-dom route component requires page reload

When calling history.push('/packages') the url is updated but the component will not mount (render) unless the page is reloaded. If I call createHistory({forceRefresh: true}) or manually reload the page the UI is rendered correctly. How can I configure react-router-dom to load the component without explicitly reloading the page or using forceRefresh?
index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import store from './store'
import {Provider} from 'react-redux'
import App from './App'
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('app')
);
App.jsx
import React, { Component } from 'react'
import { Switch, Route } from 'react-router-dom'
import PropTypes from 'prop-types'
import { Navbar, PageHeader, Grid, Row, Col } from 'react-bootstrap'
import LoginFormContainer from './components/Login/LoginFormContainer'
import PackageContainer from './components/Package/PackageContainer'
class App extends Component {
render() {
return (
<Grid>
<Navbar>
<Navbar.Header>
<Navbar.Brand><h3>Mythos</h3></Navbar.Brand>
</Navbar.Header>
</Navbar>
<Row className="content">
<Col xs={12} md={12}>
<Switch>
<Route path='/packages' render={() => <PackageContainer />} />
<Route exact path='/' render={() => <LoginFormContainer />} />
</Switch>
</Col>
</Row>
</Grid>
)
}
}
export default App
loginActions.jsx
import * as types from './actionTypes'
import LoginApi from '../api/loginApi'
import createHistory from 'history/createBrowserHistory'
const history = createHistory()
export function loginUser(user) {
return function(dispatch) {
return LoginApi.login(user).then(creds => {
dispatch(loginUserSuccess(creds));
}).catch(error => {
throw(error);
});
}
}
export function loginUserSuccess(creds) {
sessionStorage.setItem('credentials', JSON.stringify(creds.data))
history.push('/packages')
return {
type: types.LOGIN_USER_SUCCESS,
state: creds.data
}
}
PackageContainer.jsx
import React, { Component } from 'react'
import {connect} from 'react-redux'
import PropTypes from 'prop-types'
import {loadPackages} from '../../actions/packageActions'
import PackageList from './PackageList'
import ImmutablePropTypes from 'react-immutable-proptypes'
import {Map,fromJS,List} from 'immutable'
import {withRouter} from 'react-router-dom'
class PackageContainer extends Component {
constructor(props, context) {
super(props, context);
}
componentDidMount() {
this.props.dispatch(loadPackages());
}
render() {
return (
<div className="col-lg-12">
{this.props.results ?
<PackageList results={this.props.results} /> :
<h3>No Packages Available</h3>}
</div>
);
}
}
PackageContainer.propTypes = {
results: ImmutablePropTypes.list.isRequired,
};
const mapStateToProps = (state, ownProps) => {
return {
results: !state.getIn(['packages','packages','results']) ? List() : state.getIn(['packages','packages','results'])
};
}
PackageContainer = withRouter(connect(mapStateToProps)(PackageContainer))
export default PackageContainer
I assume, that issue that you are create new instance of history object but BrowserRouter doesn't know about the changes which happens inside of it.
So, you should create history object and export it in the index.jsx and use Router instead of BrowserRouter and pass as history property, so then you can just import it whenever you need.
For example:
index.jsx
import { Router } from 'react-router-dom'
import createHistory from 'history/createBrowserHistory'
...
export const history = createHistory()
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<App />
</Router>
</Provider>,
document.getElementById('app')
);
Then, in loginActions you just import history and use .push method as before.
loginActions.jsx
import * as types from './actionTypes'
import LoginApi from '../api/loginApi'
import { history } from './index'
export function loginUser(user) {
return function(dispatch) {
return LoginApi.login(user).then(creds => {
dispatch(loginUserSuccess(creds));
}).catch(error => {
throw(error);
});
}
}
export function loginUserSuccess(creds) {
sessionStorage.setItem('credentials', JSON.stringify(creds.data))
history.push('/packages')
return {
type: types.LOGIN_USER_SUCCESS,
state: creds.data
}
}
Hope it will helps.
In the App.jsx
<Switch>
<Route path='/packages' render={(props) => <PackageContainer {...props}/>} />
<Route exact path='/' render={(props) => <LoginFormContainer {...props}/>} />
</Switch>
Now both PackageContainer and LoginFormContainer have access to history object

Nesting relative routes with react-router

I have a categories index page which links to a products index page of products specific to that category. That much is functioning. But when I attempt to click on a product linked to a show component specific to that product I'm encountering trouble. Below is my code:
router.js
import React from 'react';
import { Router, Route, Switch } from 'react-router';
import createBrowserHistory from 'history/createBrowserHistory'
import App from './App';
import CategoriesIndexPage from './pages/categories/CategoriesIndexPage';
import ProductsIndexPage from './pages/products/ProductsIndexPage';
import ProductShow from './pages/products/ProductShow';
import LocationsPage from './pages/LocationsPage';
const history = createBrowserHistory()
const router = (
<Router history={history}>
<Switch>
<Route exact path='/' component={App}/>
<Route path='/categories' component={CategoriesIndexPage}/>
<Route path='/locations' component={LocationsPage}/>
<Route path='/:category' component={ProductsIndexPage}>
<Route path='/:id' component={ProductShow}/>
</Route>
</Switch>
</Router>
);
export default router;
ProductIndexPage.js
import React, { Component } from 'react';
import { BWReactData } from '../../config/FirebaseConstants.js';
import Head from '../../components/Head.js';
import Foot from '../../components/Foot.js';
import ProductsIteration from './ProductsIteration';
class ProductsIndexPage extends Component {
constructor(props){
super(props);
this.state = {
allProducts: [],
loading: true,
}
}
componentDidMount() {
...
}
render() {
let allProducts = this.state.allProducts;
let loading = this.state.loading;
let categoryURL = this.props.location.state.category;
return (
<div>
<Head/>
<ProductsIteration
allProducts={allProducts}
loading={loading}
categoryURL={categoryURL}
/>
<Foot/>
</div>
)
}
}
export default ProductsIndexPage;
ProductsIteration.js
import React from 'react';
import { Link } from 'react-router-dom';
import { Col, Row } from 'react-materialize';
const ProductsIteration = props => {
let category = props.categoryURL;
if (props.loading) {
return <div>Loading...</div>
}
return (
<Row>
{props.allProducts.map(function(object) {
return (
<Col s={12} m={6} l={3} key ={object.id}>
<div style={styles.wrapper}>
<Link to={{ pathname: `${category}/${object.id}`, state: { id: object.id }}}>
<img src={object.img} style={styles.image} />
<div style={styles.description}>
<div style={styles.descriptionContent}>{object.name}</div>
</div>
</Link>
</div>
</Col>
)
})}
</Row>
)
}
export default ProductsIteration;
The link within my iteration component renders the '/:category/:id' url in my navbar but the page does nothing. This is my first project using router and any guidance would be much appreciated.
In React Router v4:
Router components are imported from 'react-router-dom' rather than 'react-router'.
The traditional <Router/> component has been replaced with the <BrowserRouter/> component, which requires no props.
Nesting routes is no longer convention. Instead, you'll have to nest your <ProductShow/> as a component prop of a <Route/> component within a <Switch/> component within your <ProductIndexPage/> component.
See below for an example.
Router.js:
// React.
import React from 'react'
// React Router DOM.
import {
BrowserRouter as Router,
Route,
Switch
} from 'react-router-dom'
// Routes.
import App from './App'
import CategoriesIndexPage from './pages/categories/CategoriesIndexPage'
import ProductsIndexPage from './pages/products/ProductsIndexPage'
import LocationsPage from './pages/LocationsPage'
// Router.
const Router = (
<Router>
<Switch>
<Route exact path='/' component={App}/>
<Route path='/categories' component={CategoriesIndexPage}/>
<Route path='/locations' component={LocationsPage}/>
<Route path='/:category/:id?' component={ProductsIndexPage}/>
</Switch>
</Router>
)
// Export.
export default Router
ProductIndexPage.js:
// React.
import React from 'react'
// BW React Data.
import {
BWReactData
} from '../../config/FirebaseConstants.js'
// Head.
import Head from '../../components/Head.js'
// Foot.
import Foot from '../../components/Foot.js'
// Products Iteration.
import ProductsIteration from './ProductsIteration'
// Product Show.
import ProductShow from './ProductShow'
// React Router DOM.
import {
Switch
} from 'react-router-dom'
// Products Index Page.
class ProductsIndexPage extends React.Component {
// Constructor.
constructor(props){
// Super Props.
super(props)
// State.
this.state = {
allProducts: [],
loading: true,
}
}
// Did Mount.
componentDidMount() {
...
}
// Render.
render() {
let allProducts = this.state.allProducts
let loading = this.state.loading
let categoryURL = this.props.location.state.category
return (
<div>
<Head/>
<ProductsIteration
allProducts={allProducts}
loading={loading}
categoryURL={categoryURL}
/>
{this.props.match.params.id ? (<ProductShow/>) : ''}
<Foot/>
</div>
)
}
}

Resources