React router not rendering the component through history.push() - reactjs

import { React } from "react";
import { Router as MyRouter, Switch, Route } from "react-router-dom";
import NavBar from "./Components/NavBar";
import Article from "./Components/Article";
import Articles from "./Components/Articles";
var createBrowserHistory = require("history").createBrowserHistory;
const history = createBrowserHistory();
const Router = () => {
return (
<div>
<MyRouter history={history}>
<NavBar />
<Switch>
<Route exact path="/" component={Articles} />
<Route exact path="/home/:title/:id" component={Article} />
</Switch>
</MyRouter>
</div>
);
};
I have a component which display a list of articles, and if you click on one of the articles, you will be redirected to the specifics of that article. Also, article is fetching the content from the server only using the id parameter. I implemented that by using
const history = useHistory();
const onclick = (title, id) =>{
history.push(`/home/${title}/${id}`);
}
Initially, I am having no trouble at all with this structure. However, when I added a random test article, and click on it, the url changes, but the component is never rendered(I tried to log "hello world" in the Article component but it never got printed out). Strangely, if I manually put in the url localhost:3000/home/fijdaifjaid/100 with some random title and the correct id(the id that router fails to render the component for), the component is rendered with no issue, but if I manually put in the correct title it does not work.(My title is "# 1 priority")
Any suggestion on what is the problem here? Also I should note this is not a universal problem, I have several other test ids that are working fine.
My dependencies:
"react": "^17.0.2",
"react-router-dom": "^5.2.0",

Try this
import { React } from "react";
import { Router as MyRouter, Switch, Route } from "react-router-dom";
import NavBar from "./Components/NavBar";
import Article from "./Components/Article";
import Articles from "./Components/Articles";
const Router = () => {
return (
<div>
<MyRouter >
<NavBar />
<Switch>
<Route exact path="/" component={Articles} />
<Route exact path="/home/:title/:id" component={Article} />
</Switch>
</MyRouter>
</div>
);
};
Since you are using Router as a wrapper of your application, what if you don't pass the history object on the Router since you will be using the react hook useHistory().

Instead of router use browser router :
import { React } from "react";
import { BrowserRouter as MyRouter, Switch, Route } from "react-router-dom";
import NavBar from "./Components/NavBar";
import Article from "./Components/Article";
import Articles from "./Components/Articles";
// var createBrowserHistory = require("history").createBrowserHistory;
// const history = createBrowserHistory();
const Router = () => {
return (
<div>
<MyRouter basename={process.env.PUBLIC_URL}>
<NavBar />
<Switch>
<Route exact path="/" component={Articles} />
<Route exact path="/home/:title/:id" component={Article} />
</Switch>
</MyRouter>
</div>
);
};
Before making the build don't forget to add homepage in your package.json :
"homepage": "https://xxxxx.github.io",

Related

React Router useHistory Hook matching wrong component page

Below is a snippet from my app.js cra file, where I am using react-router-dom to navigate to various pages, the problem is, for /payment route, entering the url to payment: localhost:3000/checkout returns payment page component instead, useHistory with onClick on the header component also does the same, no error is thrown, I have already gone through the app twice searching for typos or any such fault.
The app.js snippet
import "./App.css";
import Home from "./Home";
import Checkout from "./Checkout";
import Login from "./Login";
import Payment from "./Payment";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
function App() {
const [state, dispatch] = useStateValue();
return (
<Router>
<div className="app">
<Switch>
<Route path="/login">
<Login />
</Route>
<Route path="/checkout">
<Checkout />
</Route>
<Route path="/payment">
<Payment />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}
the useHistory inside of a component:
import { useHistory } from "react-router-dom";
export default function Subtotal() {
const [state, dispatch] = useStateValue();
const history = useHistory();
return (
<div className="subtotal">
<button onClick={history.push("/payment")}>Proceed to checkout</button>
</div>
);
}
Quick note: everything works fine until I introduce a new route to the already existing ones
I would suggest you upgrade your react-router-dom version to v6. Since that version is much much better than v5. Version 6 has a better algorithm to select the best possible route, with the default behavior being that it matches exact routes. Also, the order in which we list the routes does not matter anymore like it did in v5 which sometimes caused issues.
Step 1: Uninstall the old version of the package and install new one
npm uninstall react-router-dom
npm install react-router-dom#6
Additionally, ensure that you have React 16.08 or higher. for react-router-dom v6 to work.
Step 2: Update the old code to the new one to make it work with the updates introduced in version 6
import "./App.css";
import Home from "./Home";
import Checkout from "./Checkout";
import Login from "./Login";
import Payment from "./Payment";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
function App() {
const [state, dispatch] = useStateValue();
return (
<Router>
<div className="app">
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/checkout" element={<Checkout />} />
<Route path="/payment" element={<Payment />} />
<Route path="/" element={<Home />} />
</Routes>
</div>
</Router>
);
}
Once these changes have been made, you will no longer face the same issue.
Also, note that the useHistory hook has been replaced with useNavigate.
Thus, in v5
import { useHistory } from "react-router-dom"
const history = useHistory();
history.push("/payment")
in v6
import { useNavigate } from "react-router-dom"
const navigate = useNavigate();
navigate("/payment")
Additionally, the way you have called history.push on onClick has to be changed
Old
onClick={history.push("/payment")}
New
onClick={() => history.push("/payment")}
Note: If you have upgraded to v6 then make use of useNavigate.
References
Upgrading from v5
Upgrading from v5 to v6 tutorial

Why is the routing not working in react.js?

I know this very basic question and yes I have looked up Google before posting it here. The solutions usually are some typo, missing the "exact" key word, not wrapping in BrowserRouter, not import something. But none of it is applicable in my case. It is probably something small but I can't figure it and is driving me a bit against the wall here.
The postJournal route doesn't work. I see it the URL but it doesn't take me to the page. The funny thing is that it worked perfectly fine and I added some other routes with /:id and since then it has stopped working.
The routes are:
import React from "react";
import "./style/App.css";
import ReactDOM from 'react-dom';
import { BrowserRouter, Switch, Router, Route } from "react-router-dom";
import HomePage from "./components/homePage"
import PostJournalEntry from "./components/postJournalEntry"
import DataByID from "./components/dataById"
function App() {
return (
<div className="app">
<BrowserRouter>
<Switch>
<Route path="/:id" exact component = {HomePage}/>
<Route path="/:id" exact component = {DataByID}/>
<Route path="/postJournal" exact component = {PostJournalEntry}></Route>
<Route path="/" exact component = {HomePage}/>
</Switch>
</BrowserRouter>
</div>
);
}
--
import React, { useState, useEffect, usePrevious } from "react";
import { Link, useParams } from "react-router-dom";
import Axios from "axios";
import HomePageListItems from "./homePageListItems";
import DataById from "./dataById";
export default function HomePage(props){
const [getAllData, setGetAllData] = useState()
const getData =async () => {
await Axios.get("http://localhost:5000/get").then((response)=>{
setGetAllData(response.data)
})
.catch((error)=>{console.log(error)})
}
useEffect(()=>{
getData();
},[])
return(
<section>
<Link to="/postJournal">Post Journal Entry</Link>
{getAllData&&getAllData.map((item)=>{
return(
<HomePageListItems
key={item.id}
idx={item.id}
name={item.name}
title={item.title}
journalEntry={item.journalEntry}
date={item.date}
file={item.file}
/>
)
})
}
{usePrevious}
<DataById/>
</section>
)
}
Thanks in advance people! Any help is appreciated
The problem in your code is the order:
<Route path="/:id" exact component = {HomePage}/>
<Route path="/:id" exact component = {DataByID}/>
<Route path="/postJournal" exact component = {PostJournalEntry}></Route>
If you write these routes in that order, your /postJournal will never be reached because /postJournal will be matched as /:id.
Just change the order, move /postJournal to the first and everything will work

How to add multiple pages with React & Redux

I'm coding a MediumBlog like application and I'm using React & redux and Django Rest Framework for my Backend. I already made the first page, which is the first page you see when you go to https://medium.com/
I'm able to navigate to different categories without refreshing the page, which is the Main Purpose of React. But now, when you want to read a post in the medium blog, the page is refreshing. I have no idea how to do it with react. I know how to build a Single Page App, but here, it seems that a new page is being loaded when you click on a post. My question is :
.Is this loading a new page instead of a new route ( a new HTML file or something )
.How can I handle this " multipage " structure with react
Here is my Single Page App that can load content from different categories
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './css/App.css';
import { Provider } from 'react-redux';
import { store } from '../store.js';
import AppHeader from './header/AppHeader';
import HeaderCategories from './header/HeaderCategories'
import PostListStream from './posts/PostListStream';
import PostList from './posts/PostList';
import { BrowserRouter } from "react-router-dom";
import { Route, Switch } from 'react-router-dom';
class App extends Component {
render(){
return(
<Provider store={store}>
<div className="App">
<AppHeader />
<HeaderCategories />
<Switch>
<Route exact
key="sciences"
path="/sciences"
render={() => <PostListStream field="sciences" />}
/>
<Route exact
key="littérature"
path="/littérature"
render={() => <PostListStream field="littérature" />}
/>
<Route exact
key="sciences-sociales"
path="/sciences-sociales"
render={() => <PostListStream field="sciences-sociales" />}
/>
</Switch>
<PostList />
</div>
</Provider>
)
}
}
ReactDOM.render(<BrowserRouter>
<App />
</BrowserRouter>, document.getElementById('app'));
Here is where my are :
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './css/App.css';
import { Provider } from 'react-redux';
import { store } from '../store.js';
import AppHeader from './header/AppHeader';
import HeaderCategories from './header/HeaderCategories'
import PostListStream from './posts/PostListStream';
import PostList from './posts/PostList';
import { BrowserRouter } from "react-router-dom";
import { Route, Switch } from 'react-router-dom';
class App extends Component {
render(){
return(
<Provider store={store}>
<div className="App">
<AppHeader />
<HeaderCategories />
<Switch>
<Route exact
key="sciences"
path="/sciences"
render={() => <PostListStream field="sciences" />}
/>
<Route exact
key="littérature"
path="/littérature"
render={() => <PostListStream field="littérature" />}
/>
<Route exact
key="sciences-sociales"
path="/sciences-sociales"
render={() => <PostListStream field="sciences-sociales" />}
/>
</Switch>
<PostList />
</div>
</Provider>
)
}
}
ReactDOM.render(<BrowserRouter>
<App />
</BrowserRouter>, document.getElementById('app'));
Thank you so much
You can create dynamic routes to your posts using react-router-dom in a similar way to what you have done with your other routes. react-router doesn't really refresh the page, although it looks like it. It simply renders another component when the route changes.
To create dynamic routes for your posts you can do something like this:
<Route
path="/post/:postId"
render={() => <PostComponent />}
/>
or like this if you want it to be a little more readable:
<Route
path="/post/:postId"
component={PostComponent}
/>
:postId here is a dynamic id, whatever is placed after /post/ in your URL will be considered the postId by react-router.
Inside your PostComponent you can do something like this to fetch your postId variable:
import { withRouter } from "react-router-dom";
const PostComponent = withRouter(props => (
const postId = props.match.params.postId;
return ();
))
You can then use your postId to fetch your post from the backend and do whatever you need to do with it. As soon as you go to your post URL now, it will show the PostComponent without hard refreshing the page.

React Router not rendering component at path, returns blank page with correct pathing

React-Router appears to be working in my app except for the fact that I am getting a blank page instead of my component, even though it is directed to the proper path.
I'm scanning the documentation but I can't resolve the issue on my own after looking it over and searching Google/this site.
I had tried...
Making it so that the router.js file just contained the routes only to get the same results. Specifying exact path as well when doing so.
Reinstalling react-router-dom into the component in case there was an error when it downloaded.
Removing the provider in case that was the issue
Placing the code in the router file directly in the App.js file between the provider component tags
These are the files involved.
Router.js
import React from 'react';
import {Route, Switch, Redirect} from 'react-router-dom';
import LandingPage from '../scenes/LandingPage';
import CityPage from '../scenes/CityPage';
const Router = () => {
return (
<Switch>
<Redirect from='/' to='/landing' />
<Route path='/landing' component={LandingPage} />
<Route path='/citypage' component={CityPage} />
</Switch>
);
}
export default Router;
App.js
import React from "react";
import { BrowserRouter } from "react-router-dom";
import Router from "./services/Router";
import ChosenCityContextProvider from "./services/context/ChosenCityContext";
const App = () => {
return (
<BrowserRouter>
<ChosenCityContextProvider>
<Router />
</ChosenCityContextProvider>
</BrowserRouter>
);
};
export default App;
No error messages accompany the rendering of the site. Aside from the blank page, everything else appears to be working. In the React Dev tools, it states that the Router.Consumer has an object which is revealed to empty when expanded.
What is wrong with my code?
https://codesandbox.io/s/youthful-maxwell-rch1k?fontsize=14
Above is sandbox of code. I have the same issue here
I'm not certain why exactly this fixes the issue, but I've run into this on a work project so knew it worked.
If you add exact into the redirect element it forces the correct behavior.
import React from 'react';
import {Route, Switch, Redirect} from 'react-router-dom';
import LandingPage from '../scenes/LandingPage';
import CityPage from '../scenes/CityPage';
const Router = () => {
return (
<Switch>
<Redirect exact from='/' to='/landing' />
<Route path='/landing' component={LandingPage} />
<Route path='/citypage' component={CityPage} />
</Switch>
);
}
export default Router;
I tried this and it worked. I'm not sure why before it didn't. If anyone has an explanation please let me know because I am trying to learn what I did wrong initially.
<Route render={() => <Redirect from='/' to='/landing' />} />
I added the above, so my router file looked like this.
import React from 'react';
import {Route, Switch, Redirect} from 'react-router-dom';
import LandingPage from '../scenes/LandingPage';
import CityPage from '../scenes/CityPage';
const Router = () => {
return (
<Switch>
<Route path='/landing' component={LandingPage} />
<Route path='/citypage' component={CityPage} />
<Route render={() => <Redirect from='/' to='/landing' />} />
</Switch>
);
}
export default Router;
#DLowther has also showed me another solution
import React from "react";
import { Route, Switch, Redirect } from "react-router-dom";
import Page from "./Page";
import Home from "./Home";
const Router = () => {
return (
<Switch>
<Redirect exact from="/" to="/home" />
<Route path="/home" component={Home} />
<Route path="/page" component={Page} />
</Switch>
);
};
export default Router;
I would like to credit this individual for answering my question

How to properly dynamically change information displayed in a website based on URL?

I'm new to JavaScript and React. I seem to be stuck on this question, I have found information but I think that this is not what I'm really looking for perhaps someone can shed some light on the matter.
So what I'm really looking for is a way to create a "mold" page of an node/react app that will display changing information based on the URL a user submits. Say for example look at facebook (or even stackoverflow) one click on a profile of friends 'y' then the url changes to facebook.com/friends-y and if we choose another person it then changes. Thus I believe that's how they must know how to fill their template using the info provided from that URL with names pictures etc.
I saw that a blog suggests to use route another suggest using url queries more so (which I don't know how to read them once given or how to render them say such as with a onChange event sort of thing when say you click on something inside the page).
My question is: Are any of this methods useful, should I combine them I seen websites that uses both or is there another industry standard that i haven't found and perhaps comes with react?
Any guidance would be much appreciated.
First of all i assume that you have multiple component and you want to change from one component to another component via url. so you have to install react router dom
npm install --save react-router-dom
and after then import Router, Route, Link, Switch (whatever you want) from react-router-dom and give route to component inside router tag .... i mention below in my code
import React, { Component } from 'react';
import './App.css';
import Login from './component/login';
import User from './component/user';
import Signup from './component/signup';
import Notfound from './component/notfound';
import { BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
const Home = () => (
<div>
<h2>Home</h2>
</div>
);
class App extends Component {
constructor(props){
super(props);
this.state={
loggedIn : false
}
}
render() {
return (
<Router>
<div className="App">
<ul className="nav nav-pills">
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/login">LogIn</Link>
</li>
<li>
<Link to="/signup">Sign Up</Link>
</li>
<li>
<Link to="/user">User</Link>
</li>
</ul>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/login" component={Login} />
<Route path="/signup" component={Signup} />
<Route path="/user" component={User} onEnter={this.requireAuth}/>
<Route path="*" component={Notfound} />
</Switch>
</div>
</Router>
);
}
}
export default App;
note : in my code i have total 5 component in my project
Login,
User,
Signup,
NotFound,
Home
for more router information you can check in this site. https://reacttraining.com/react-router/web/example/basic
import React , {Component} from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import App from './Components/Home/App'
import Digital from './Components/DigitalStrat/Digital-Strat';
import ServiceLines from './Components/Serviceline/ServiceLines';
import Operations from './Components/OperationTransformation/Operations-
Transformation';
import WhyUs from './Components/WhyUs/Why-us';
import Mission from './Components/Mission/Mission';
import OurGroup from './Components/OurGroup/OurGroup';
import Team from './Components/Team/Team';
import Projects from './Components/Projects/Projects';
import Research from './Components/Research/Research';
import News from './Components/News/News';
import Locations from './Components/Location/Locations';
import registerServiceWorker from './registerServiceWorker';
import NewsDetails from "./Components/NewsDetails/newsDetails";
import i18n from './js/i18n'
import { sliderArrow } from './js/sliderArrow';
import { menu } from './js/menu';
import {withRouter} from 'react-router';
import Coockies from './Components/Cookies/Cookies';
class ScrollToTop extends Component {
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
window.scrollTo(0, 0)
}
}
render() {
return this.props.children
}
}
export default withRouter(ScrollToTop);
ReactDOM.render(
<BrowserRouter>
<Switch>
<ScrollToTop>
<Route exact path = "/" component = {App} />
<Route exact path='/index.html' component={App}/>
<Route exact path='/Digital-Strategies.html' component={Digital} />
<Route exact path='/Service-Lines.html' component={ServiceLines} />
<Route exact path='/Operations-Transformation.html' component=
{Operations}/>
<Route exact path='/inside-the-company.html' component={WhyUs}/>
<Route exact path='/Mission.html' component={Mission}/>
<Route exact path='/Our-group.html' component={OurGroup}/>
<Route exact path='/Team.html' component={Team}/>
<Route exact path='/Projects.html' component={Projects}/>
<Route exact path ='/Research-Development.html' component = {Research}/>
<Route exact path='/News.html' component={News}/>
<Route exact path='/news-details.html/:slug' component={NewsDetails}/>
<Route exact path='/Locations.html' component={Locations}/>
<Route exact path='/cookies' component={Coockies} />
</ScrollToTop>
</Switch>
</BrowserRouter>, document.getElementById('root'));
registerServiceWorker();
This is the basic way to route the project. Feel free to ask question.
The way to handle routing in React is with React Router.
With this sort of (virtual) routing there are two main ways that routing needs to be handled.
1. The first is by rendering different components when the url changes—for example rendering a <Home/> component for "/" and an <About/> component for "/about".
An example:
import React, { Component } from 'react';
import { Switch, Route, withRouter } from 'react-router-dom';
import Home from "./pages/Home";
import About from "./pages/About";
class App extends Component {
render() {
return (
<Switch>
<Route exact path="/" component={ Home }/>
<Route path="/about" component={ About }/>
</Switch>
)
}
}
export default withRouter(App);
2. The second case, which I believe your question specifically addresses, is rendering the same component with different data depending on the url—for example having a <Profile/> component but changing its data for "/profiles/1" vs "/profiles/2".
An example:
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
class Profile extends Component {
constructor() {
super();
this.state = {
profileData: {}
}
}
componentDidMount() {
this.fetchData();
}
componentDidUpdate(prevProps) {
const currentId = this.props.match.params.id;
const prevId = prevProps.match.params.id;
if (currentId !== prevId) {
this.fetchData();
}
}
async fetchData() {
const profileId = this.props.match.params.id;
const profileData = await fetch(`http://example.com/api/profiles/${profileId}`);
this.setState({
profileData
});
}
render() {
const { profileData } = this.state;
return (
<div>
<h1>{ profileData.name }</h1>
</div>
)
}
}
export default withRouter(Profile);
Where the containing parent component of <Profile/> has a <Route/> that looks like this:
<Route path="/profiles/:id" component={ Profile }/>
Which is important so that the id is in this.props.match.params.
Note that in the above example the way to check what data to use to populate the view is by checking the :id parameter in the url. Since information about the url is passed to the <Profile/> component as a prop, we can check if the url changes in componentDidUpdate and get new data if there was a change.
Finally, both of these involve a bit of setup with React Router (basically just wrapping your <App/> in a <Router/>) but the documentation should help with that: https://reacttraining.com/react-router/web/guides/quick-start.
Hopefully this helps.

Resources