How to navigate to other page using react router - reactjs

I have a onClick function to navigate to other page. I tried this.props.history.push("/SecondPage/ID/") and some examples but nothing worked out.
I have the component like this:
export class MainPage extends Component {
constructor(props) {
super(props);
}
render(){
return (
<div id="main" onClick={this.NavigatetoOtherPage.bind(this)}>
)
}
NavigatetoOtherPage(){
let ID = this.props.ID; // I need to pass the ID as a parameter.
//Here I need to navigate to other page using. I can use window.location.href but I need to use react router.
}
}
export default connect(state => {
return {
ID: state.Reducer.ID,
};
})(MainPage)
My app.js file like this
export default class App extends Component {
render() {
return (
<Provider store={store}>
<Route exact path='/' component={MainPage}/>
<Route path='/SecondPage/:ID/' component = {SecondPage} />
</Provider>
);
}
}
My index.js page like this
export function renderPage() {
ReactDOM.render(
<Router>
<App />
</Router>
, document.getElementById('root'));
}
renderPage();
How can I navigate to second page without window.location.href

You can use the useHistory hook or the Link component given you are using react-router-dom
import React from "react";
import { useHistory, Link } from "react-router-dom";
// Then in your component
const MainPage = (props) => {
/**
* hooks
*/
const history = useHistory();
/**
* function
*/
const handleNavigation = () => {
let ID = props.ID; // I need to pass the ID as a parameter.
history.push(`/dashboard/${ID}`)
}
return (
<button id="main" onClick={() => history.push("/")}> Go to / </button>
<button id="main" onClick={() => handleNavigation()}> Go to dynamic page
</button>
<Link to={`/dashboard/${props.ID}`} className="some-styling">
Using Link
</Link>
);
};
// I have merged both implementations
export default MainPage;
// Edited: Based on the comment, the issue is "The history is not coming in the props."
// Then you could use `withRouter` HOC, and then there will be
// the `history` object in the wrapped component's props.
import {withRouter} from 'react-router-dom';
class MainPage extends React.Component {
render(){
console.log(this.props.history) // history object
return(<div />)
}
}
export default withRouter(MainPage)`

Wrote down a small sandbox. I guess this is what you are trying to achieve.
https://codesandbox.io/s/practical-tereshkova-ilbig?file=/src/App.js

Related

Catch Data from URL params in react class Compoent

First of all I like to convey thanks all the wise programmer. After updating react react-router-dom i am facing this problem. Here i want to mention one thing that, i am a "class component" lover.
However, This is my base component in react.
import React, { Fragment, Component } from 'react'
import axios from 'axios'
import { Col , Row} from 'react-bootstrap'
import { Link } from 'react-router-dom'
export default class Blog extends Component {
constructor(props) {
super(props)
this.state = {
data:[]
}
}
componentDidMount()
{
axios.get("https://jsonplaceholder.typicode.com/posts")
.then((response)=>{
if(response.status===200)
{
this.setState({
data:response.data
})
}
})
.catch((error)=>{})
}
render() {
const allData = this.state.data;
const blogFull = allData.map((val)=>{
var title = val.title;
var body = val.body;
var id = val.id;
return(
<Col key={id} lg={4}>
<Link to={"/post/"+id}><h1>{title}</h1></Link>
<p>{body}</p>
</Col>
)
})
return (
<Fragment>
<Row>
{blogFull}
</Row>
</Fragment>
)
}
}
and this is my next component
import axios from 'axios'
import React, { Component, Fragment } from 'react'
import { useParams } from 'react-router'
export default class Post extends Component {
constructor(props) {
super(props)
this.state = {
mydata:[],
}
}
componentDidMount()
{
axios.get("https://jsonplaceholder.typicode.com/posts/")
.then((response)=>{
if(response.status===200)
{
this.setState({
mydata:response.data
})
}
})
.catch((error)=>{
})
}
render() {
const dataAll = this.state.mydata;
return (
<Fragment>
data retriving
<h1>{dataAll.title}</h1>
<p>{dataAll.body}</p>
</Fragment>
)
}
}
My Route is here :
<Routes>
<Route exact path="/" element={<Blog/>}/>
<Route exact path="/post/:id" element={<Post/>}/>
</Routes>
Can anyone tell me that how can i get data in post component from base component via its url parameter? The "match" object is not working in current update of react-router-dom. I want help for class component.
Issue
In react-router-dom v6 the Route components no longer have route props (history, location, and match), and the current solution is to use the React hooks "versions" of these to use within the components being rendered. React hooks can't be used in class components though.
To access the match params with a class component you must either convert to a function component, or roll your own custom withRouter Higher Order Component to inject the "route props" like the withRouter HOC from react-router-dom v5.x did.
Solution
I won't cover converting a class component to function component. Here's an example custom withRouter HOC:
const withRouter = WrappedComponent => props => {
const params = useParams();
// etc... other react-router-dom v6 hooks
return (
<WrappedComponent
{...props}
params={params}
// etc...
/>
);
};
And decorate the component with the new HOC.
export default withRouter(Post);
This will inject a params prop for the class component.
this.props.params.id

Reactjs - how to pass props to Route?

I’m learning React Navigation using React-Router-Dom. I have created a simple app to illustrate the problem:
Inside App.js I have a Route, that points to the url “/” and loads the functional Component DataSource.js.
Inside DataSource.js I have a state with the variable name:”John”. There is also a buttonwith the onclick pointing to a class method that’s supposed to load a stateless component named ShowData.js using Route.
ShowData.js receives props.name.
What I want to do is: when the button in DataSource.js is clicked, the url changes to “/showdata”, the ShowData.js is loaded and displays the props.name received by DataSource.js, and DataSource.js goes away.
App.js
import './App.css';
import {Route} from 'react-router-dom'
import DataSource from './containers/DataSource'
function App() {
return (
<div className="App">
<Route path='/' component={DataSource}/>
</div>
);
}
export default App;
DataSource.js
import React, { Component } from 'react';
import ShowData from '../components/ShowData'
import {Route} from 'react-router-dom'
class DataSource extends Component{
state={
name:' John',
}
showDataHandler = ()=>{
<Route path='/showdata' render={()=><ShowData name={this.state.name}/>}/>
}
render(){
return(
<div>
<button onClick={this.showDataHandler}>Go!</button>
</div>
)
}
}
export default DataSource;
ShowData.js
import React from 'react';
const showData = props =>{
return (
<div>
<p>{props.name}</p>
</div>
)
}
export default showData;
I have tried the following, but, even though the url does change to '/showdata', the DataSource component is the only thing being rendered to the screen:
DataSource.js
showDataHandler = ()=>{
this.props.history.push('/showdata')
}
render(){
return(
<div>
<button onClick={this.showDataHandler}>Go!</button>
<Route path='/showdata' render={()=>{<ShowData name={this.state.name}/>}}/>
</div>
)
}
I also tried the following but nothing changes when the button is clicked:
DataSource.js
showDataHandler = ()=>{
<Route path='/showdata' render={()=>{<ShowData name={this.state.name}/>}}/>
}
render(){
return(
<div>
<button onClick={this.showDataHandler}>Go!</button>
</div>
)
}
How can I use a nested Route inside DataSource.js to pass a prop to another component?
Thanks.
EDIT: As user Sadequs Haque so kindly pointed out, it is possible to retrieve the props when you pass that prop through the url, like '/showdata/John', but that's not what I'd like to do: I'd like that the url was just '/showdata/'.
He also points out that it is possible to render either DataSource or ShowData conditionally, but that will not change the url from '/' to '/showdata'.
There were multiple issues to solve and this solution worked as you wanted.
App.js should have all the routes. I used Route params to pass the props to ShowData. So, /showdata/value would pass value as params to ShowData and render ShowData. And then wrapped the Routes with BrowserRouter. And then used exact route to point / to DataSource because otherwise DataSource would still get rendered as /showdata/:name has /
DataSource.js will simply Link the button to the appropriate Route. You would populate DataSourceValue with the appropriate value.
ShowData.js would read and display value from the router prop. I figured out the object structure of the router params from a console.log() of the props object. It ended up being props.match.params
App.js
import { BrowserRouter as Router, Route } from "react-router-dom";
import DataSource from "./DataSource";
import ShowData from "./ShowData";
function App() {
return (
<div className="App">
<Router>
<Route exact path="/" component={DataSource} />
<Route path="/showdata/:name" component={ShowData} />
</Router>
</div>
);
}
export default App;
DataSource.js
import React, { Component } from "react";
import ShowData from "./ShowData";
class DataSource extends Component {
state = {
name: " John",
clicked: false
};
render() {
if (!this.state.clicked)
return (
<button
onClick={() => {
this.setState({ name: "John", clicked: true });
console.log(this.state.clicked);
}}
>
Go!
</button>
);
else {
return <ShowData name={this.state.name} />;
}
}
}
export default DataSource;
ShowData.js
import React from "react";
const ShowData = (props) => {
console.log(props);
return (
<div>
<p>{props.name}</p>
</div>
);
};
export default ShowData;
Here is my scripts on CodeSandbox. https://codesandbox.io/s/zen-hodgkin-yfjs6?fontsize=14&hidenavigation=1&theme=dark
I figured it out. At least, one way of doing it, anyway.
First, I added a route to the ShowData component inside App.js, so that ShowData could get access to the router props. I also included exact to DataSource route, so it wouldn't be displayed when ShowData is rendered.
App.js
import './App.css';
import {Route} from 'react-router-dom'
import DataSource from './containers/DataSource'
import ShowData from './components/ShowData'
function App() {
return (
<div className="App">
<Route exact path='/' component={DataSource}/>
{/* 1. add Route to ShowData */}
<Route path='/showdata' component={ShowData}/>
</div>
);
}
export default App;
Inside DataSource, I modified the showDataHandler method to push the url I wanted, AND added a query param to it.
DataSource.js
import React, { Component } from 'react';
class DataSource extends Component{
state={
name:' John',
}
showDataHandler = ()=>{
this.props.history.push({
pathname:'/showdata',
query:this.state.name
})
}
render(){
return(
<div>
<button onClick={this.showDataHandler}>Go!</button>
</div>
)
}
}
export default DataSource;
And, finally, I modified ShowData to be a Class, so I could use state and have access to ComponentDidMount (I guess is also possible to use hooks here, if you don't want to change it to a Class).
Inside ComponentDidMount, I get the query param and update the state.
ShowData.js
import React, { Component } from 'react';
class ShowData extends Component{
state={
name:null
}
componentDidMount(){
this.setState({name:this.props.location.query})
}
render(){
return (
<div>
<p>{this.state.name}</p>
</div>
)
}
}
export default ShowData;
Now, when I click the button, the url changes to '/showdata' (and only '/showdata') and the prop name is displayed.
Hope this helps someone. Thanks.

TypeError: instance.render is not a function while using react-router-dom

Hi If any one can help. Thanks in advance
In console I am also getting this
index.js:1 Warning: AppBootUp(...): No render method found on the returned component instance: you may have forgotten to define render
this is my App.js
import React from "react";
import AppRoutes from "../routes/routers";
import { createStore } from 'redux'
import rootReducer from '../store/reducers/index'
import {Provider} from "react-redux";
const store = createStore(rootReducer);
export default class AppBootUp extends React.Component<> {
static render() {
return (
<Provider store={store}>
<AppRoutes/>
</Provider>
);
}
}
this is my AppRoutes
import React from "react";
import { BrowserRouter as Router, Redirect, Route, Switch } from "react-router-dom";
import Login from "../components/Login/login"
const routesConfig = [
{
path: "/",
component: Login,
name: "Login",
exact: true
}
];
const AppRoutes = () => {
return (
<Router>
<Switch>
{routesConfig.map(config => {
return (
<Route
exact={config.exact && true}
key={`${config.name}`}
path={config.path}
render={(props) => {
const ComponentToRender = config.component;
return <ComponentToRender {...props} />;
}}
/>
);
})}
<Redirect to="/" />
</Switch>
</Router>
);
};
export default AppRoutes;;
this is login.js
import React from "react";
export default class Login extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<p>
hello
</p>
</div>
);
}
}
I am using react-router-dom. I think, I am missing something little here.
Remove static method from render method in AppBootUp class. If you define a render method as static, it won't be available in class instance, which is why you are getting this error.
export default class AppBootUp extends React.Component<> {
render() {
return (
<Provider store={store}>
<AppRoutes/>
</Provider>
);
}
}
You need to remove static before render method of AppBootUp.
render shouldn't be a static property of React class component otherwise it won't exist on component's instance and would become unavailable.
As static properties don't exist on class instance but on the Class itself.
Remove static before render in Appboot.
render should not be a static property of React class component otherwise it won't exist on component's instance.
As static properties don't exist on class instance but on the Class itself.
Normally this happens when you accidentally alt+enter on render in Webstorm.
when it shows warning that this method can be static.

React-router custom prop not passing to component. ternary operator not working correctly

In React i have my App.js page where i keep my states. I'm importing user1.js component to App.js, and in user1.js component i have a link button that takes me to path /user2.
When i click the button, React will set state property called testValue to true and in user2.js page ternary operator should choose the first value - test works because of that. But for some reason it does not work.
Any help?
APP.JS
import React, { Component } from 'react';
import './App.css';
import User1 from './components/user1';
class App extends Component {
constructor(props){
super(props);
this.state = {
testValue:false
};
}
change = () => {
this.setState({
testValue:true
},() => {
console.log(this.state.testValue)
});
}
render() {
return (
<div className="App">
<User1 change={this.change}/>
</div>
);
}
}
export default App;
USER1.JS
import React from 'react';
import { BrowserRouter, Route, Switch, Link } from 'react-router-dom';
import User2 from './user2.js';
const User1 = (props) => {
return(
<BrowserRouter>
<div>
<Link to ="/user2">
<button onClick={props.change}>Next page</button>
</Link>
<Switch>
<Route path="/user2" exact component={User2}/>
</Switch>
</div>
</BrowserRouter>
); // end of return
};
export default User1;
USER2.JS
import React from 'react';
const User2 = (props) => {
console.log(props)
return(
<div>
{props.testValue ?
<p>test works</p>
:
<p>test does not work</p>
}
</div>
);
};
export default User2;
This is what i expected - test works
This is what i got - test does not work
You want to pass a custom property through to a component rendered via a route. Recommended way to do that is to use the render method.
<Route path="/user2" exact render={(props) => <User2 {...props} testValue={true} />} />
I think a valid inquiry here would be what are you wanting to pass through as an extra prop? whats the use case here? You may be trying to pass data in a way you shouldn't (context would be nice :D).

How to redirect an user to a different url when history object of react-router is not accessible

How should I redirect an user to a different url when I cannot get an access to history props of react-router?
What I want to do is when an user clicks an log-out link on the navigation menu, the user get redirected to the root path '/'.
handleAuthentication(event) {
this.props.toggleAuthenticationStatus(() => {
// I want to redirect an user to the root path '/' in this callback function.
});
}
handleAuthentication method is called when an user clicks an login/logout link on the navigation menu.
toggleAuthenticationStatus(callback) {
this.setState((prevState, props) => {
return { isLoggedIn: !prevState.isLoggedIn }
},
callback()
);
}
Then, when handleAuthentication method in the NavigationMenu Component, it calls toggleAuthenticationStatus method in App Component that changes the state of Login/Logout and run callback function which is defined in the handleAuthentication method in the NavigationMenu Component.
Is it ok to run "window.location.href = '/'" directly?
Does it mess up the react-router history object???
Could anyone please how I should implement user redirect in a right way?
App Component
import React, { Component } from 'react';
import NavigationMenu from './NavigationMenu';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Secret from './Secret';
import Top from './Top';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: false
};
this.toggleAuthenticationStatus = this.toggleAuthenticationStatus.bind(this);
}
toggleAuthenticationStatus(callback) {
this.setState((prevState, props) => {
return { isLoggedIn: !prevState.isLoggedIn }
},
callback()
);
}
render() {
return (
<BrowserRouter>
<div>
<NavigationMenu isLoggedIn={this.state.isLoggedIn} toggleAuthenticationStatus={this.toggleAuthenticationStatus} />
<Switch>
<Route path='/secret' render={(props) => <Secret isLoggedIn={this.state.isLoggedIn} {...props} />} />
<Route path='/' component={Top} />
</Switch>
</div>
</BrowserRouter>
)
}
}
NavigationMenu Component
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
class NavigationMenu extends Component {
constructor(props) {
super(props);
this.handleAuthentication = this.handleAuthentication.bind(this);
}
handleAuthentication(event) {
this.props.toggleAuthenticationStatus(() => {
// I want to redirect an user to the root path '/' in this callback function.
});
}
render() {
return (
<ul>
<li><Link to='/'>Top</Link></li>
<li><Link to='/secret'>Secret</Link></li>
<li><Link to='/login' onClick={this.handleAuthentication}>
{this.props.isLoggedIn === true ? 'Logout' : 'Login'}
</Link></li>
</ul>
)
}
}
export default NavigationMenu;
I found the method 'withRouter' in react-router.
This seems the solution in my situation.
I'm going to try using it.
https://reacttraining.com/react-router/web/api/withRouter
You can get access to the history object’s properties and the closest
's match via the withRouter higher-order component. withRouter
will re-render its component every time the route changes with the
same props as render props: { match, location, history }.

Resources