Get url params in ReactJS when using class component - reactjs

This is my URL in react js
http://localhost:3000/meassger/student/1
I want to extract 1 from the URL if it was a functional component I could have used ```useParams``
I am getting this error
TypeError: Cannot read properties of undefined (reading 'params')
componentDidMount() {
console.log(this.props.match.params.id, "");
};

You need to wrap it in withRouter - that injects the URL variables into your props.
You can find an example here: https://stackoverflow.com/a/60316195/13063136
The code:
import React from "react";
import { withRouter } from "react-router";
class ShowTheID extends React.Component {
const { match } = this.props;
componentDidMount() {
console.log(match.params.id)
}
render() {
return <div>{match.params.id}</div>;
}
}
const ShowTheIDWithRouter = withRouter(ShowTheID);
Note: Along with wrapping your component in withRouter you also need to make sure that your route is registered and you have mentioned URL params in your Route path like path="/meassger/student/:id"

Let's assume we have a url like http://localhost:3000/student/:studentId and we need to grab studentId param from this url
In a functional component, we can do it like
import React from 'react';
import { useParams } from 'react-router-dom';
const Student = () => {
const { studentId } = useParams();
return (
<div>StudentId: { studentId }</div>
);
}
export default Student;
In a class based component, we can do it like
import React, { Component } from 'react';
class Student extends Component {
render() {
const { studentId } = this.props.match.params;
return (
<div>StudentId: { studentId }</div>
);
}
}
export default Student;
Alternatively, you can use withRouter HOC. By doing so, you can also access location and history props.
import React, { Component } from 'react';
import { withRouter } from "react-router";
class Student extends Component {
render() {
const { location, history } = this.props;
return (
<React.Fragment>
<div>StudentId: { match.studentId }</div>
<div>Path: {location.pathname}</div>
</React.Fragment>
);
}
}
const StudentWithRouter = withRouter(Student);

In functional component, use
const history = useHistory()
const studentId = history?.location?.pathname.split('/')[3]
In class component, use
const studentId = window.location.href.split('/')[3]

Related

How can i get a parameter value in React to use it in the url of an api fetch? [duplicate]

I'm trying to load a details view based on a react-router-dom route that should grab the URL parameter (id) and use that to further populate the component.
My route looks like /task/:id and my component loads fine, until I try to grab the :id from the URL like so:
import React from "react";
import { useParams } from "react-router-dom";
class TaskDetail extends React.Component {
componentDidMount() {
let { id } = useParams();
this.fetchData(id);
}
fetchData = id => {
// ...
};
render() {
return <div>Yo</div>;
}
}
export default TaskDetail;
This triggers the following error and I'm unsure where to correctly implement useParams().
Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
The docs only show examples based on functional components, not class based.
Version <= 5:
You can use withRouter to accomplish this. Simply wrap your exported classed component inside of withRouter and then you can use this.props.match.params.id to get the parameters instead of using useParams(). You can also get any location, match, or history info by using withRouter. They are all passed in under this.props
Using your example it would look like this:
import React from "react";
import { withRouter } from "react-router";
class TaskDetail extends React.Component {
componentDidMount() {
const id = this.props.match.params.id;
this.fetchData(id);
}
fetchData = id => {
// ...
};
render() {
return <div>Yo</div>;
}
}
export default withRouter(TaskDetail);
Simple as that!
import React, { Component } from "react";
import { useParams } from "react-router-dom";
function withParams(Component) {
return props => <Component {...props} params={useParams()} />;
}
class TaskDetail extends React.Component {
componentDidMount() {
let { id } = this.props.params;
this.fetchData(id);
}
fetchData = id => {
// ...
};
render() {
return <div>Yo</div>;
}
}
export default withParams(TaskDetail);
Since hooks wont work with class based components you can wrap it in a function and pass the properties along:
class TaskDetail extends React.Component {
componentDidMount() {
const { id } = this.props.params;
// ...
}
}
export default (props) => (
<TaskDetail
{...props}
params={useParams()}
/>
);
But, like #michael-mayo said, I expect this is what withRouter is already performing.
Params get passed down through props on the match object.
props.match.params.yourParams
source: https://redux.js.org/advanced/usage-with-react-router
Here is an example from the docs destructing the props in the arguments.
const App = ({ match: { params } }) => {
return (
<div>
<AddTodo />
<VisibleTodoList filter={params.filter || 'SHOW_ALL'} />
<Footer />
</div>
)
}
You can not call a hook such as "useParams()" from a React.Component.
Easiest way if you want to use hooks and have an existing react.component is to create a function then call the React.Component from that function and pass the parameter.
import React from 'react';
import useParams from "react-router-dom";
import TaskDetail from './TaskDetail';
function GetId() {
const { id } = useParams();
console.log(id);
return (
<div>
<TaskDetail taskId={id} />
</div>
);
}
export default GetId;
Your switch route will still be something like
<Switch>
<Route path="/task/:id" component={GetId} />
</Switch>
then you will be able to get the id from from the props in your react component
this.props.taskId
In react-router-dom-v6 you can easily use useParams() in functional components but when it gets to the class component you have to create HOC (higher-order component) because hooks don't support class components:
import { useNavigate, useParams } from "react-router-dom";
export const withRouter = (WrappedComponent) => (props) => {
const params = useParams();
const navigate = useNavigate();
return <WrappedComponent {...props} params={params} navigate={navigate} />;
};
Then export your component from your HOC and give your component as a parameter. like below:
export default withRouter(YourComponentName);
After that you can easily access the url id with this.props.params.id and you can navigate to other components with this.props.navigate("/YourPath")
React Route v5
Query params can be read and processed as JSON using withRouter and queryString as follow:
import React from "react";
import { withRouter } from "react-router";
import queryString from 'query-string';
class MyComponent extends React.Component {
componentDidMount() {
const params = queryString.parse(this.props.location.search);
console.log('Do something with it', params);
}
render() {
return <div>Hi!</div>;
}
}
export default withRouter(MyComponent);
SmujMaiku is rigth!!! His answer works perfectly. This is how work today with react-router v6
enter code here
import React ,{Component} from 'react'
import { useParams } from "react-router-dom";
import PokeDescription from '../components/PokeDescription'
class PokeInfoConteiner extends Component{
render(){
let urlPokemon= "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/"
const {idPokemon} = this.props.params
console.log(idPokemon)
return(
<div>
<PokeDescription pokeImage={`${urlPokemon}${idPokemon}.png?raw=true`}/>
<p>{}</p>
</div>
)
}
}
export default (props) => (
<PokeInfoConteiner
{...props}
params={useParams()}
/>)
in React Router V6 :
import React, {Component} from 'react';
import {useParams} from 'react-router-dom';
/* This is a higher order component that
* inject a special prop to our component.
*/
function withRouter(Component) {
function ComponentWithRouter(props) {
let params = useParams()
return <Component {...props} params={params} />
}
return ComponentWithRouter
}
class TaskDetail extends React.Component {
state={
id : ""
}
componentDidMount() {
this.setState({
id : this.props.params.id
})
}
static getDerivedStateFromProps(nextProps) {
return {
id : nextProps.params.id
}
}
fetchData = id => {
// ...
};
render() {
return <div>Yo</div>;
}
}
const HOCTaskDetail = withRouter(TaskDetail);
export default HOCTaskDetail;
React Route v6
My friends, I tried to use in class but I failed to find any doc about it. So after many hours of searching and trying hard this is (in function). Now (i.e when I'm writing this post) there is only limited resource about v6. But there are many for <v6.
Here I'm using useState,useEffect,useParams,axios.
import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import axios from 'axios';
const Post = () => {
let { post_id } = useParams();
const [posts, setPosts] = useState({ post: null, countSecrets: 0, ui: '' });
useEffect(() => {
if (posts.countSecrets === 0) {
const doAxe = (a) => {
axios.get('https://jsonplaceholder.typicode.com/posts/' + post_id)
.then((res) => {
setPosts(s => ({ ...s, value: res.data }));
doUI(res.data)
// console.log(res.data)
});
}
setPosts(s => ({ ...s, countSecrets: s.countSecrets + 1 }));
doAxe()
}
}, [posts, post_id]);
let doUI = (x) => {
// console.log('x' + x.title)
const finalPost = (x !== null) ? (
<div className="post">
<h4 className="center">{x.title}</h4>
<p>{x.body}</p>
</div>
) : (
<div className="center">Loading posts...</div>
);
setPosts(s => ({ ...s, ui: finalPost }));
}
return (
<div className="container">
{posts.ui}
</div>
);
}
export default Post;
NOTE:
I faced useEffect looping. I prevented it with a key.
HOPE: This may help someone!
Reference:
using useParams
state inside function
preventing loop from useEffect
In react-router-dom v6, there is no hook such as withRouter therefore my advice to you is to convert your class-based component to a functional component to use useParams hook in your component otherwise you can create a higher-order component to pass your class-based component.
as you know the useParams() is a hook for react-router-dom.
you can not use this inside the componentDidMount() or useEffect() because both of them are method that called during the Mounting phase of the React Life-cycle i.e after the component is rendered.
you have a solution:
create or define another function outside the componentDidMount() to define useParams then call it inside the componentDidMount.
know every thing will be ok.
This is my working example. :)
import React, { Component } from "react";
import { useParams } from "react-router-dom";
function withParams(Component) {
return (props) => <Component {...props} params={useParams()} />;
}
class ProductDetails extends Component {
handleSave = () => {
// Navigate to /products
};
render() {
return (
<div>
<h1>Product Details - {this.props.params.id}</h1>
<button onClick={this.handleSave}>Save</button>
</div>
);
}
}
export default withParams(ProductDetails);
Hooks only work on functional components,
you have to make that ocmponent a functional component
Fixed by creating a wrapping function
I needed to pass params to my SaxjaxApp.js from index.js using react-router-dom v6.
In v6 Switch has been changed to Routes
I got the useParams working with a class component by following Mohamed MAZEK's idea in post 20 using a wrapping function.
I needed to access the sessionId part of the url when it was available.
ie in localhost:3000/shared/123XYZId
I needed the 123XYZId part.
make note of this line : <Route path="/shared/:sessionId" element={<SaxjaxAppWrapper />} /> in the index.js below.
:sessionId denotes that useParams has a property called sessionId, that can be accessed by:
const {sessionId} = useParams() from a functional component.
In my index.js file I did this:
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import "./styles/style.scss";
import SaxjaxAppWrapper from "SaxjaxAppWrapper";
import SaxjaxApp from "./SaxjaxApp";
const container = document.getElementById("root");
const root = ReactDOM.createRoot(container);
//INFO: to learn about react-roue-dom v6 https://reactrouter.com/en/v6.3.0/upgrading/v5
root.render(
// <React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/shared/:sessionId" element={<SaxjaxAppWrapper />} />
<Route path="/" element={<SaxjaxApp />} />
</Routes>
</BrowserRouter>
// </React.StrictMode>
);
This line <Route path="/shared/:sessionId" element={<SaxjaxAppWrapper />} /> calls my wrapping function, whereas the default path / just calls the class component.
I had to create a separate file to hold the wrapping function I don't know why:
import React from "react";
import { useParams } from "react-router-dom";
import SaxjaxApp from "SaxjaxApp";
function SaxjaxAppWrapper() {
//I use the params here and store them to pass as props
let { sessionId } = useParams();
return (
//I pass the sessionId from the url params as a prop to my SaxjaxApp class component here
<SaxjaxApp sessionId={sessionId} />
);
}
export default SaxjaxAppWrapper;
My class component:
import React, { Component } from "react";
import "./styles/style.scss";
class SaxjaxApp extends Component {
state = {
octave: 4,
};
constructor(props) {
super(props);
//... initialise stuff
}
//... a lot of methods
render() {
//Access the param here
const { sessionId } = this.props;
<>
<div>
keybordId={sessionId ? sessionId : "no id was passed"}
</div>
</>
);
}
}
export default SaxjaxApp;

React passing array from component to useState child (modal). Like to pass in as array and return it as array so can save

I have the following parent React component. I would like to either pass the meeting.settings.ae (array of object) to the child useState Component. Don't know how I can fix it.
import React, {Component} from 'react';
import AEModal from "./AEModal";
export default class MAT extends Component {
constructor(props) {
super(props);
this.state = {
ae: !!meeting.settings.ae ? meeting.settings.ae : ""
};
}
getMeetingAEArray = () => {
let setting = this.state.settings();
return !!setting && !!setting.ae ? setting.ae : null;
}
getMeetingAE = () => {
return <AEModal
meeting={() => {
return this.state.meeting;
}}
AEArray={() => {
return getMeetingAEArray();
}}
/>
}
}
The child class
import React, { useState } from "react";
import i18n from 'Components/translations/i18n';
import {
Icon,
} from '#components';
function AEModal(props) {
const [form, setForm] = useState([]);
let meeting = props.meeting();
let ae = meeting.settings.ae; //ae is undefined
let aeArray = props.getAEArray();
}
To pass props coming from parent, you can do it as follows.
Following is an example. Please modify it for your implementation.
import React, { Component } from "react";
import AEModal from "./AEModal";
export default class MAT extends Component {
render() {
return (
<AEModal
meeting={this.props.meeting}
/>
);
};
}
Child component
import React, { useState } from "react";
function AEModal(props) {
console.log("meeting: ", props.meeting);
return <div>{props.meeting}</div>;
}

Getting data as a Class Component rather than a Hook

I'm using Auth0, and can grab the data using hooks like so:
const { user } = useAuth0()
How can I refactor and get that same data in a Class Component? I just cannot figure it out or find a good example. I've tried:
this.state = { user: useAuth0()}
But no luck...
auth0-react provides a HOC withAuth0 which you can use with class components as mentioned here
import React, { Component } from 'react';
import { withAuth0 } from '#auth0/auth0-react';
class Profile extends Component {
render() {
// `this.props.auth0` has all the same properties as the `useAuth0` hook
const { user } = this.props.auth0;
return <div>Hello {user.name}</div>;
}
}
export default withAuth0(Profile);
Wrapper function component outside class component;
const AuthWrapper = (E)=> {
const WrapperComponent = (props)=> {
const { user } = useAuth0()
return <E user={user} {...props} />
}
return WrapperComponent;
}
Class Component
#AuthWrapper
class AuthDemo extends Component {
render() {
const { user } = this.props;
...
}
}
you need to use higher order component to implements.
more details: use-with-a-class-component

react-router-dom useParams() inside class component

I'm trying to load a details view based on a react-router-dom route that should grab the URL parameter (id) and use that to further populate the component.
My route looks like /task/:id and my component loads fine, until I try to grab the :id from the URL like so:
import React from "react";
import { useParams } from "react-router-dom";
class TaskDetail extends React.Component {
componentDidMount() {
let { id } = useParams();
this.fetchData(id);
}
fetchData = id => {
// ...
};
render() {
return <div>Yo</div>;
}
}
export default TaskDetail;
This triggers the following error and I'm unsure where to correctly implement useParams().
Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
The docs only show examples based on functional components, not class based.
Version <= 5:
You can use withRouter to accomplish this. Simply wrap your exported classed component inside of withRouter and then you can use this.props.match.params.id to get the parameters instead of using useParams(). You can also get any location, match, or history info by using withRouter. They are all passed in under this.props
Using your example it would look like this:
import React from "react";
import { withRouter } from "react-router";
class TaskDetail extends React.Component {
componentDidMount() {
const id = this.props.match.params.id;
this.fetchData(id);
}
fetchData = id => {
// ...
};
render() {
return <div>Yo</div>;
}
}
export default withRouter(TaskDetail);
Simple as that!
import React, { Component } from "react";
import { useParams } from "react-router-dom";
function withParams(Component) {
return props => <Component {...props} params={useParams()} />;
}
class TaskDetail extends React.Component {
componentDidMount() {
let { id } = this.props.params;
this.fetchData(id);
}
fetchData = id => {
// ...
};
render() {
return <div>Yo</div>;
}
}
export default withParams(TaskDetail);
Since hooks wont work with class based components you can wrap it in a function and pass the properties along:
class TaskDetail extends React.Component {
componentDidMount() {
const { id } = this.props.params;
// ...
}
}
export default (props) => (
<TaskDetail
{...props}
params={useParams()}
/>
);
But, like #michael-mayo said, I expect this is what withRouter is already performing.
Params get passed down through props on the match object.
props.match.params.yourParams
source: https://redux.js.org/advanced/usage-with-react-router
Here is an example from the docs destructing the props in the arguments.
const App = ({ match: { params } }) => {
return (
<div>
<AddTodo />
<VisibleTodoList filter={params.filter || 'SHOW_ALL'} />
<Footer />
</div>
)
}
You can not call a hook such as "useParams()" from a React.Component.
Easiest way if you want to use hooks and have an existing react.component is to create a function then call the React.Component from that function and pass the parameter.
import React from 'react';
import useParams from "react-router-dom";
import TaskDetail from './TaskDetail';
function GetId() {
const { id } = useParams();
console.log(id);
return (
<div>
<TaskDetail taskId={id} />
</div>
);
}
export default GetId;
Your switch route will still be something like
<Switch>
<Route path="/task/:id" component={GetId} />
</Switch>
then you will be able to get the id from from the props in your react component
this.props.taskId
In react-router-dom-v6 you can easily use useParams() in functional components but when it gets to the class component you have to create HOC (higher-order component) because hooks don't support class components:
import { useNavigate, useParams } from "react-router-dom";
export const withRouter = (WrappedComponent) => (props) => {
const params = useParams();
const navigate = useNavigate();
return <WrappedComponent {...props} params={params} navigate={navigate} />;
};
Then export your component from your HOC and give your component as a parameter. like below:
export default withRouter(YourComponentName);
After that you can easily access the url id with this.props.params.id and you can navigate to other components with this.props.navigate("/YourPath")
React Route v5
Query params can be read and processed as JSON using withRouter and queryString as follow:
import React from "react";
import { withRouter } from "react-router";
import queryString from 'query-string';
class MyComponent extends React.Component {
componentDidMount() {
const params = queryString.parse(this.props.location.search);
console.log('Do something with it', params);
}
render() {
return <div>Hi!</div>;
}
}
export default withRouter(MyComponent);
SmujMaiku is rigth!!! His answer works perfectly. This is how work today with react-router v6
enter code here
import React ,{Component} from 'react'
import { useParams } from "react-router-dom";
import PokeDescription from '../components/PokeDescription'
class PokeInfoConteiner extends Component{
render(){
let urlPokemon= "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/"
const {idPokemon} = this.props.params
console.log(idPokemon)
return(
<div>
<PokeDescription pokeImage={`${urlPokemon}${idPokemon}.png?raw=true`}/>
<p>{}</p>
</div>
)
}
}
export default (props) => (
<PokeInfoConteiner
{...props}
params={useParams()}
/>)
in React Router V6 :
import React, {Component} from 'react';
import {useParams} from 'react-router-dom';
/* This is a higher order component that
* inject a special prop to our component.
*/
function withRouter(Component) {
function ComponentWithRouter(props) {
let params = useParams()
return <Component {...props} params={params} />
}
return ComponentWithRouter
}
class TaskDetail extends React.Component {
state={
id : ""
}
componentDidMount() {
this.setState({
id : this.props.params.id
})
}
static getDerivedStateFromProps(nextProps) {
return {
id : nextProps.params.id
}
}
fetchData = id => {
// ...
};
render() {
return <div>Yo</div>;
}
}
const HOCTaskDetail = withRouter(TaskDetail);
export default HOCTaskDetail;
React Route v6
My friends, I tried to use in class but I failed to find any doc about it. So after many hours of searching and trying hard this is (in function). Now (i.e when I'm writing this post) there is only limited resource about v6. But there are many for <v6.
Here I'm using useState,useEffect,useParams,axios.
import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import axios from 'axios';
const Post = () => {
let { post_id } = useParams();
const [posts, setPosts] = useState({ post: null, countSecrets: 0, ui: '' });
useEffect(() => {
if (posts.countSecrets === 0) {
const doAxe = (a) => {
axios.get('https://jsonplaceholder.typicode.com/posts/' + post_id)
.then((res) => {
setPosts(s => ({ ...s, value: res.data }));
doUI(res.data)
// console.log(res.data)
});
}
setPosts(s => ({ ...s, countSecrets: s.countSecrets + 1 }));
doAxe()
}
}, [posts, post_id]);
let doUI = (x) => {
// console.log('x' + x.title)
const finalPost = (x !== null) ? (
<div className="post">
<h4 className="center">{x.title}</h4>
<p>{x.body}</p>
</div>
) : (
<div className="center">Loading posts...</div>
);
setPosts(s => ({ ...s, ui: finalPost }));
}
return (
<div className="container">
{posts.ui}
</div>
);
}
export default Post;
NOTE:
I faced useEffect looping. I prevented it with a key.
HOPE: This may help someone!
Reference:
using useParams
state inside function
preventing loop from useEffect
In react-router-dom v6, there is no hook such as withRouter therefore my advice to you is to convert your class-based component to a functional component to use useParams hook in your component otherwise you can create a higher-order component to pass your class-based component.
as you know the useParams() is a hook for react-router-dom.
you can not use this inside the componentDidMount() or useEffect() because both of them are method that called during the Mounting phase of the React Life-cycle i.e after the component is rendered.
you have a solution:
create or define another function outside the componentDidMount() to define useParams then call it inside the componentDidMount.
know every thing will be ok.
This is my working example. :)
import React, { Component } from "react";
import { useParams } from "react-router-dom";
function withParams(Component) {
return (props) => <Component {...props} params={useParams()} />;
}
class ProductDetails extends Component {
handleSave = () => {
// Navigate to /products
};
render() {
return (
<div>
<h1>Product Details - {this.props.params.id}</h1>
<button onClick={this.handleSave}>Save</button>
</div>
);
}
}
export default withParams(ProductDetails);
Hooks only work on functional components,
you have to make that ocmponent a functional component
Fixed by creating a wrapping function
I needed to pass params to my SaxjaxApp.js from index.js using react-router-dom v6.
In v6 Switch has been changed to Routes
I got the useParams working with a class component by following Mohamed MAZEK's idea in post 20 using a wrapping function.
I needed to access the sessionId part of the url when it was available.
ie in localhost:3000/shared/123XYZId
I needed the 123XYZId part.
make note of this line : <Route path="/shared/:sessionId" element={<SaxjaxAppWrapper />} /> in the index.js below.
:sessionId denotes that useParams has a property called sessionId, that can be accessed by:
const {sessionId} = useParams() from a functional component.
In my index.js file I did this:
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import "./styles/style.scss";
import SaxjaxAppWrapper from "SaxjaxAppWrapper";
import SaxjaxApp from "./SaxjaxApp";
const container = document.getElementById("root");
const root = ReactDOM.createRoot(container);
//INFO: to learn about react-roue-dom v6 https://reactrouter.com/en/v6.3.0/upgrading/v5
root.render(
// <React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/shared/:sessionId" element={<SaxjaxAppWrapper />} />
<Route path="/" element={<SaxjaxApp />} />
</Routes>
</BrowserRouter>
// </React.StrictMode>
);
This line <Route path="/shared/:sessionId" element={<SaxjaxAppWrapper />} /> calls my wrapping function, whereas the default path / just calls the class component.
I had to create a separate file to hold the wrapping function I don't know why:
import React from "react";
import { useParams } from "react-router-dom";
import SaxjaxApp from "SaxjaxApp";
function SaxjaxAppWrapper() {
//I use the params here and store them to pass as props
let { sessionId } = useParams();
return (
//I pass the sessionId from the url params as a prop to my SaxjaxApp class component here
<SaxjaxApp sessionId={sessionId} />
);
}
export default SaxjaxAppWrapper;
My class component:
import React, { Component } from "react";
import "./styles/style.scss";
class SaxjaxApp extends Component {
state = {
octave: 4,
};
constructor(props) {
super(props);
//... initialise stuff
}
//... a lot of methods
render() {
//Access the param here
const { sessionId } = this.props;
<>
<div>
keybordId={sessionId ? sessionId : "no id was passed"}
</div>
</>
);
}
}
export default SaxjaxApp;

Get URL pathname in nextjs

I have a signin page and layout component.Layout component has header.I don't want to show header in signin .and for that I want to get url pathname.based on pathname show the header .
import * as constlocalStorage from '../helpers/localstorage';
import Router from 'next/router';
export default class MyApp extends App {
componentDidMount(){
if(constlocalStorage.getLocalStorage()){
Router.push({pathname:'/app'});
} else{
Router.push({pathname:'/signin'});
}
}
render() {
const { Component, pageProps } = this.props
return (
//I want here pathname for checking weather to show header or not
<Layout>
<Component {...pageProps} />
</Layout>
)
}
}
please help
If you want to access the router object inside any functional component in your app, you can use the useRouter hook, here's how to use it:
import { useRouter } from 'next/router'
export default function ActiveLink({ children, href }) {
const router = useRouter()
const style = {
marginRight: 10,
color: router.pathname === href ? 'red' : 'black',
}
const handleClick = e => {
e.preventDefault()
router.push(href)
}
return (
<a href={href} onClick={handleClick} style={style}>
{children}
</a>
)
}
If useRouter is not the best fit for you, withRouter can also add the same router object to any component, here's how to use it:
import { withRouter } from 'next/router'
function Page({ router }) {
return <p>{router.pathname}</p>
}
export default withRouter(Page)
https://nextjs.org/docs/api-reference/next/router#userouter
You can use asPath property, that will give you the path (including the query) shown in the browser without the configured basePath or locale:
const { asPath } = useRouter()
Suppose the complete URL of a page is 'abc.com/blog/xyz' and the component file name matching with this route is './pages/blog/[slug].js'
useRouter() hook returns a route object, which has two properties to get the pathname.
One is asPath property, and
Another one is pathname property.
asPath property contains pathname extracted from the URL i.e. /blog/xyz
but pathname property contains the pathname of your project directory i.e. /blog/[slug].
Example Implementation
// .pages/blog/[slug].js
import { useRouter } from 'next/router';
const BlogSlug = () => {
const { asPath, pathname } = useRouter();
console.log(asPath); // '/blog/xyz'
console.log(pathname); // '/blog/[slug]'
return (
<div></div>
);
}
export default BlogSlug;
To fully use the SSR out-of-the-box provided by Next.js, you can use the context object provided in getInitialProps and which contains the pathname. You can then pass this pathname to be used as a props by your component.
For example:
class Page extends React.Component {
static getInitialProps({ pathname }){
return { pathname }
}
render() {
return <div>{this.props.pathname === 'login' ? 'good' : 'not good'}</div>
}
}
Might be late but just use router.pathname
function MyComp() {
const router = useRouter();
return (
<a className={router.pathname === '/some-path' ? 'currentCSS' : 'defaultCSS'}>
Some link
</a>
);
}
One cannot access the Router or the useRouter() options to access the current path in app.js file. This is not client side rendered and hence the only way to access you current path would be to pass it from your getInitialProps() or the getServerSideProps() call to your App component, and then access it there to develop your logic based on the current route.
My app needed to have multiple documents, so I also was looking for a way to get the path name, with nextjs, default document
This is a way that I found, which works for me.
import Document, { Html, Head, Main, NextScript } from 'next/document'
import { LandingPage, WithSidePanels } from '../documents'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
console.log(this.props.__NEXT_DATA__.page)
if(this.props.__NEXT_DATA__.page === "/") return <LandingPage />
return (
<WithSidePanels />
)
}
}
export default MyDocument
So this.props.__NEXT_DATA__.page this is going to give you, the path name, "/", or "/contact" or whatever,
from the _document.js :)
For whom who are searching for an example:
import React, { Component } from "react";
import { withRouter } from 'next/router'
class Login extends Component {
constructor(props) {
super(props);
}
onClickHandler = (event) => {
this.props.router.push('/newPage')
}
render() {
return (
<div>
<p>Hello, {this.props.router.pathname}</p>
<button onClick={this.onClickHandler}>Click me!</button>
</div>
);
}
}
export default withRouter(Login);
Probably to avoid use import Router from 'next/router' in nextjs
you may use
import {useRouter} from 'next/router';

Resources