props are not accessible in the function component - reactjs

Inside user.js file the props are coming as empty I am unable to access the match in props. I don't understand why props is coming as empty object.
App.js file
import "./App.css"
import { BrowserRouter as Router, Route, Routes, Link } from 'react-router-dom'
import Home from "./components/Home";
import About from "./components/About";
import User from "./components/User";
function App() {
return (
<div className="container">
<Router>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/user/john">User</Link>
</li>
</ul>
<div>
<Routes>
<Route exact path="/" element={<Home/>}></Route>
<Route exact path="/about" element={<About/>} ></Route>
<Route exact path="/user/:name" element={<User/>}></Route>
</Routes>
</div>
</Router>
</div>
);
}
export default App;
user.js file
import React from 'react'
function User({match}){
return (
<div>
User - {match.params.name}
</div>
)
}
export default User
Inside user.js file the props are coming as empty I am unable to access the match object in props. I don't understand why props is coming as empty object.

The User component isn't passed any props:
element={<User/>} // <-- no props are passed to User
With the way routed components are rendered in react-router-dom v6.x now they no longer are passed props (history, location, and match, or any others) and these must now be accessed via their respective hooks.
history object is now a navigate function and accessed via useNavigate
location object accessed via useLocation
match object accessed via useMatch
However, the route params accessed directly via the useParms hook!
For a give route:
<Route exact path="/user/:name" element={<User/>} />
User can use the useParams hook to access the name route path parameter:
import React from 'react';
import { useParams } from 'react-router-dom';
function User() {
const { name } = useParams();
return (
<div>
User - {name}
</div>
)
}

You have to use the hook useMatch hook to access the current match.

Related

React not rendering Route Components

I am building a consumer facing app with a admin dashboard. I want to keep the routing separate for them and so trying to delegate :-
App.js
import React, {Component} from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
//styles
import './style/bootstrap/bootstrap.scss';
//apps
import Mainapp from './mainapp/Mainapp';
import Admin from './admin/Admin';
const MainappContainer = () => (
<Mainapp />
);
const AdminContainer = () => (
<Admin />
);
class App extends Component{
render(){
return (
<Router>
<Switch>
<Route path="/admin" component={AdminContainer}/>
<Route path="/" component={MainappContainer}/>
</Switch>
</Router>
)
}
}
export default App;
Admin.js
import React, {Component} from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
//styles
import './admin-style.scss';
//layout
import ControlPanel from './component/layout/ControlPanel';
import Navbar from './component/layout/Navbar';
//pages
import Quote from './component/pages/quote/Quote';
class Admin extends Component{
render(){
return (
<div className="adminWrapper">
<ControlPanel />
<section className="viewPanel">
<Navbar />
<Router>
<Route path="/quote" component={Quote}/>
</Router>
</section>
</div>
)
}
}
export default Admin;
However when I hit the URL
http://localhost:3000/admin/quote
it doesn't seem to load the quote component
Quote.js
import React, { Component } from 'react';
class Quote extends Component {
render() {
return (
<div className="float-right pr-3">
<h3>
Quote Page
</h3>
</div>
)
}
}
export default Quote;
When dealing with nested subroutes, the easiest solution is to use match.
path - (string) The path pattern used to match. Useful for building nested
Routes.
url - (string) The matched portion of the URL. Useful for building
nested Links.
By design, components placed inside a Route's component render method are given several additional props from react-router-dom. Among them are history and match. You can leverage these props to either to match against sub routes and/or to control browser history location.
In addition, you only need one instance of BrowserRouter sitting at the top-level of the application, then you can use Switch to optionally render any main or sub routes. And you don't need to use class components unless you're utilizing state and/or a class field.
A very basic, rudimentary working example of your application:
src/components/Admin/index.js
import React from "react";
import { Switch, Link, Route } from "react-router-dom";
import ControlPanel from "../ControlPanel";
import Quote from "../Quote";
// since Admin is placed inside a Route's component render
// method, it has access to history and match
function Admin({ history, match }) {
return (
<div className="adminWrapper">
<ControlPanel />
<section className="viewPanel">
<Link to={`${match.url}/quote`}>View quote</Link>
<br />
<Switch>
<Route exact path={`${match.path}/quote`} component={Quote} />
</Switch>
</section>
<br />
<button type="button" onClick={() => history.goBack()}>
Go Back
</button>
</div>
);
}
export default Admin;
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Link, Route, Switch } from "react-router-dom";
import Admin from "./components/Admin";
const linkStyle = {
padding: "0 10px"
};
function App() {
return (
<BrowserRouter>
<Link style={linkStyle} to="/">
Home
</Link>
<Link style={linkStyle} to="/admin">
Admin
</Link>
<Switch>
<Route path="/admin" component={Admin} />
<Route path="/" render={() => <h1>Main App</h1>} />
</Switch>
</BrowserRouter>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
Follow the Nested Routing Example
The main changes you need to do are:
1. Remove the <Router></Router> from Admin component and
2. Prepend match.path to "/quotes", like it is done in Topics component in the example. In the example, Topics is a function component so it is receiving match as function parameter. As your Admin component is class component, you can access it as this.props.match in render method.
<Route path={`${this.props.match.path}/quote`} component={Quote}/>
<Route exact path="/admin" component={AdminContainer}/>
<Route exact path="/admin/quote" component={Quote}/>
This won't route you to /admin/quote instead it will route you to /admin/admin/quote.
Since it is inside admin just /quote is enough
<Route path="/admin" component={AdminContainer}/>
<Route path="/quote" component={Quote}/>

not getting location react router?

id like to change my header color when in my contact page. unable to get location from react router. I get "TypeError: Cannot read property 'pathname' of undefined".
I know I'm missing something simple but i cant seem to figure it out.
import React from 'react';
import './Header.css';
import { NavLink } from 'react-router-dom';
class Header extends React.Component {
render() {
const blackHeader = {"background-color" : 'black'}
const clearHeader = {"background-color" : 'transparent'}
return(
<header style={ this.props.location.pathname === '/Contact' ? { blackHeader } : { clearHeader } }>
<NavLink to={'/'}><h2>Name</h2></NavLink>
<nav>
<ul>
<li><NavLink to={'/'}>Portfolio</NavLink></li>
<li><NavLink to={'Contact'}>Contact</NavLink></li>
<li>Blog</li>
</ul>
</nav>
</header>
)
}
}
export default Header;
You need to pass the location props to your Header component or you can use the HOC withRouter in react-router-dom.
import { NavLink, withRouter } from 'react-router-dom';
export default withRouter(Header)
Edit for clarity:
If you render a component in your router in a Route component:
<Route path='/' component={Home} />
This will give that component (Home in this case) access to the location props which can then be passed to children of that component.
import React, { Component } from 'react'
import OtherComponent from './OtherComponent'
class Home extends Component {
render() {
return (
<div>
<OtherComponent locations={this.props.locations}
</div>
)
}
}
export default Home;
However, if the component is not passed through Route it will not have access to location props. For example, if you put your header outside of your routes, something like:
<Router>
<Header/>
<Switch>
<Route path='/' component={Home}/>
</Switch>
</Router>
It will not have location props.
I'm not sure how your component tree is set up but, I hope this gives a little clarity to how the location props are accessed and used in your app.
The documentation is a good place to get some more clarity on the workings of react router as well https://reacttraining.com/react-router/core/api/Route/route-props
Yea, I can see in the contact path
<li><NavLink to={'Contact'}>Contact</NavLink></li> ,
it should be something like
<li><NavLink to='/Contact'>Contact</NavLink></li>.
You have to include the back slash, I mean this ' / ' before the pathname. So try it now.

How to link to Routes inside the component rendered by another Route with React Router

i'm trying to use react router in my reactjs app. And I encountered this problem:
This is what i'm trying to do:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import About from '../Pages/About';
import Home from '../Pages/Home';
import Topics from '../Pages/Topics';
import LinkTest from '../Pages/LinkTest';
class AppRouter extends Component {
render() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/home">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
<Route path="/home" component={LinkTest}/>
</ul>
<hr />
<Route path="/home" component={Home}/>
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</div>
</Router>
);
}
}
export default AppRouter;
Ignore "about" and "topic" component, when I click on "Home" link, it should target 2 routes, one will render "LinkTest" and the other renders "Home".
This is what inside "LinkTest":
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
class LinkTest extends Component {
render() {
const {match}=this.props;
return (
<div>
<Link to={`${match.url}/Test`}>Link To Test</Link>
</div>
);
}
}
export default LinkTest;
And inside my "Home" component:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import Test from './Test';
class Home extends Component {
render() {
const {match} = this.props;
console.log(match.url);
return (
<Router>
<div>
<h2>
Hello from Home page
<Link to={`${match.url}/Test`}>Link To Test</Link>
<Route path={`${match.url}/Test`} component={Test}/>
</h2>
</div>
</Router>
);
}
}
export default Home;
However:
When i click on the link inside "LinkTest" component (which was rendered earlier), the url on the browser is shown "http://localhost:3000/home/Test", but nothing happens.
When i clicked on the link inside "Home" component, (which was rendered the same time as the "LinkTest" using the same link), it showed the same url on the browser: "http://localhost:3000/home/Test", only this time it rendered the "Test" component.
Why does this happen? (what i want to achieve is I want to use the link inside "LinkTest" to render "Test" component inside "Home" component, or something similar).
I hope this is clear enough.
You can do it in following way:
<Route exact path='/a' component={A} />
<Route path='/b' component={B} />
// Following should be router inside Component B
<Route exact path='/b/abc' component={OtherComponent}
If you want I've prepared few react-router 4 examples. These are hosted here. https://github.com/SandipNirmal/react-router-examples
If you need Nested routing inside ComponentB you should add Links for those Routes as well. And use match.url and match.path to build the nested Links and Routes.
const ComponentB = ({ match }) => {
return (
<div>
<div>
<ul>
<li><Link to={`${match.url}/c`}>Component C</Link></li>
// more Links
<li><Link to={`${match.url}/css`}>CSS</Link></li>
<li><Link to={`${match.url}/react`}>React</Link></li>
</ul>
</div>
<div>
<Route path={`${match.path}/c`} component={ComponentC} />
// more nested Routes
<Route path={`${match.path}/css`} render={() => { return <h1>CSS</h1> }}/>
<Route path={`${match.path}/react`} render={() => { return <h1>React</h1> }}/>
</div>
</div>
);
}
Nested routing
Components created via Route will automatically be passed the following prop objects: match, location and history.
Using match you can implement nested Routes. The match object contains the following properties:
params — (object) Key/value pairs parsed from the URL corresponding
to the dynamic segments of the path
isExact — (boolean) true if the entire URL was matched (no trailing characters)
path — (string) The path pattern used to match. Useful for building nested Routes
url — (string) The matched portion of the URL. Useful for building
nested Links
Reference
https://medium.freecodecamp.org/beginners-guide-to-react-router-4-8959ceb3ad58
https://medium.com/#pshrmn/a-simple-react-router-v4-tutorial-7f23ff27adf

can i change routing onmouseenter event in react js?

when i click the Link router Link works perfectly but how can i access router link onmouseenter event please suggest me.its kind of a hover effect.when i hovered the router link menu its active and go to the link destination.
import React, { Component } from 'react';
import './App.css';
import "../node_modules/bootstrap/dist/css/bootstrap.min.css";
import Example from './Example.js';
import About from "./About.js";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
class App extends Component {
render() {
return <div className="App">
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
<hr />
<Route exact path="/" component={Example} />
<Route path="/about" component={About} />
</div>
</Router>
<Example />
</div>;
}
}
export default App;
Doesnt seem like a good idea changing history state onmouseover.
Anyways for your scenario call below within onmouseeenter:
this.props.history.push(newUrl);
Components added to route will have history as props. For eg: Below Example component will have history as props
<Route exact path="/" component={Example} />
Other components not added to route mostly child components won't have history as prop. To get access to react-router history we use #withRouter decorator in our project. There is an option available if decorators are not used. To use decorators add "stage-3" of babel in your project.
Update:
import { withRouter } from "react-router";
#withRouter
class App extends Component {
...
}
Add history to props. Now within component use: this.props.history.push(newUrl);

How to pass props to a router?

I have a file route.js which has
import React from 'react'
import { render } from 'react-dom'
import {HashRouter ,Route,Link} from 'react-router-dom'
const Router = (props) => (
<HashRouter>
<div>
<Route exact path="/" render={() => <list data={props.data}/>}/>
<Route path="/list" render={() => <Table data={props.data}/>}/>
</div>
</HashRouter>
here is the edit page code-
import React, { Component} from 'react'
export default class Edit extends Component {
render() {
return (
<div>
<center>{this.props.data}</center>
</div>
);
}
}
i want to pass the list data to the next page.how can i pass props to page from router
If you want to pass any props to some route you can just pass it through the params prop of Link.
Here in your case you could just set a button anywhere on the FreindList page which should be like:
<Link to='edit' params={{data: props.data.name}}>
<button>Edit</button>
</Link>
Further you can access this array in the edit page aswel.
don not forget to import Link from react router
Since you are using react-router-dom which is react router 4, you can just use, something like this:
<Link to={{
pathname: '/edit',
state: { data: props.data.name }
}}>
<button>Edit</button>
</Link>
You will get it in this.props.location.state in the edit component.
For more documentation on react router 4 check this out

Resources