how to pass props one page to another page via react router? - reactjs

In my React app I'm using react-router-dom. In App.js I have set my routes. There I have three components: /home, /customerinfo and /success.
In the home component I have a button. What I want is that when I press the button, the customerinfo component will load in full page and I want the state of the home component in the customerinfo component. This is what my Route looks like:
<Route
path="/customerInfo"
render={props => <CustomerInfo {...props} />}
/>
But I don't have access of the state of the home component in App.js, so it's not working.
How can I get the state of the home component in customerinfo?
I'm new in React. Please help me.

Use redux to pass data for complex application.
But if you want to stick around using react only then you could pass data using props to Redirect Component.
When CustomerInfo button is clicked data from home Controller is passed down to customerInfo component.
import React from "react";
import { BrowserRouter as Router, Route, Link, Redirect } from "react-router-dom";
function BasicExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
</ul>
<hr />
<Route exact path="/" component={Home} />
<Route path="/customerinfo" component={CustomerInfo} />
</div>
</Router>
);
}
class Home extends React.Component {
state = {
redirect: false,
data: 'data passed through home route to customer info route'
};
handleClick = () => {
this.setState({
redirect: true
})
}
render () {
if (this.state.redirect) {
return <Redirect to={{
pathname: '/customerinfo',
state: { data: this.state.data }
}} />
} else {
return (
<div>
<h2>Home</h2>
<button onClick={this.handleClick}>CustomerInfo</button>
</div>
);
}
}
}
function CustomerInfo({ location }) {
console.log(location)
return (
<div>
<h2>{location.state.data}</h2>
</div>
);
}
export default BasicExample;
Hope that helps!!!

Related

React-router URL changes but page is still unchanged

I am new to react and react-router, so please go easy on me.
I am trying to implement router in my Todo List project, where path="/" takes me to my todo list and path="/id" takes me to a test page (later will show the description of the task).
When I click the link that takes me to "/id", the URL in the browser changes but the page/content doesn't. However, when I refresh my browser, the test page loads.
I have put the Switch in App.js shown below.
import React, { Component } from "react";
import "./App.css";
import TodoList from "./components/TodoList";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import Test from "./components/Test";
class App extends Component {
render() {
return (
<Router>
<div className="todo-app">
<p>
<Link to="/">Home</Link>
</p>
<Switch>
<Route exact path="/" component={TodoList} />
<Route path={`/id`} component={Test} />
</Switch>
</div>
</Router>
);
}
}
export default App;
And I have put the Link to "/id" as shown below in a child component of component which is called here in App.js.
<div key={todo.id}>
<Link className="todo-text" to={`/id/${todo.id}`}>
{todo.text}
</Link>
</div>
Am I missing something which is causing my component to not load when I click the link?
Edit: Here's a link to my project. https://stackblitz.com/edit/react-7cpjp9?file=src/index.js
Issue
Ok, the issue is exactly as I had suspected. You are rendering multiple routers in your app. The first is a BrowserRouter in your index.js file, the second, another BrowserRouter in App.js, and at least a third BrowserRouter in Todo.js. You need only one router to provide a routing context for the entire app.
The issue here is that the router in Todo component is the closest router context to the links to specific todo details. When a link in Todo is clicked, this closest router handles the navigation request and updates the URL in the address bar. The blocks, or "masks", the router in App component or index.js that is rendering the routes from "seeing" that a navigation action occurred. In other words, the URL in the address bar is updated by the inner router, but the outer router doesn't know to render a different route.
Solution
Keep the BrowserRouter wrapping App in index.js and remove all other routers used in your app.
App - Remove the Router component. Also, reorder the routes/paths from most specific to least specific so you don't need to specify the exact prop on every route. Allows more specific paths to be matched and rendered before less specific paths by the Switch component.
class App extends Component {
render() {
return (
<div className="todo-app">
<p>
<Link to="/">Home</Link>
</p>
<Switch>
<Route path="/id/:todoId" component={Test} />
<Route path="/" component={TodoList} />
</Switch>
</div>
);
}
}
Todo - Remove the Router component. Move the key={todo.id} up to the outer-most element so when todos array is updated React can reconcile updates.
class Todo extends Component {
constructor(props) {
super(props);
this.state = {
id: null,
value: "",
details: "",
};
this.submitUpdate = this.submitUpdate.bind(this);
}
submitUpdate(value) {
const { updateTodo } = this.props;
updateTodo(this.state.id, value);
this.setState({
id: null,
value: "",
});
}
render() {
const { todos, completeTodo, removeTodo } = this.props;
if (this.state.id) {
return <TodoForm edit={this.state} onSubmit={this.submitUpdate} />;
}
return todos.map((todo, index) => (
<div
className={todo.isComplete ? "todo-row complete" : "todo-row"}
key={todo.id}
>
<div>
<Link className="todo-text" to={`/id/${todo.id}`}>
{todo.text}
</Link>
</div>
<div className="icons">
<RiCloseCircleLine
onClick={() => removeTodo(todo.id)}
className="delete-icon"
/>
<TiEdit
onClick={() => this.setState({ id: todo.id, value: todo.text })}
className="edit-icon"
/>
<RiCheckboxCircleLine
onClick={() => completeTodo(todo.id)}
className="delete-icon"
/>
</div>
</div>
));
}
}
First of all the approach, you are taking for dynamic routing is wrong.
It should be like this you will have to add the exact keyword on the dynamic route.
<Route exact path="/id/:todoId" component={Test} />
And
<div key={todo.id}>
<Link className="todo-text" to={`/id/${todo.id}`}>
{todo.text}
</Link>
import React, { Component } from "react";
import "./App.css";
import TodoList from "./components/TodoList";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import Test from "./components/Test";
class App extends Component {
render() {
return (
<Router>
<div className="todo-app">
<p>
<Link to="/">Home</Link>
</p>
<Switch>
<Route exact path="/" component={TodoList} />
**<Route exact path={`/id`} component={Test} />**
</Switch>
</div>
</Router>
);
}
}
export default App;

Binding state to Route Switch

I am building a React app that fetches JSON data from an API call and feeds the response into an app state called menus [] as follows:
App.js
import React,{Component} from 'react';
import Menus from './components/menus';
class App extends Component {
state = {
menus: []
}
componentDidMount(){
fetch('api url')
.then(res => res.json())
.then((data)=> {
this.setState({menus: data})
})
.catch(console.log)
}
render(){
return (
<div>
<Menus menus={this.state.menus} />
</div>
);
}
}
export default App;
Im using the state in a simple component that contains a route switch as follows:
Menus.js
import React from 'react';
import {BrowserRouter as Router, Switch, Route, Link, useParams } from "react-router-dom";
const Menus = ({ menus }) => {
return (
<Router>
<div>
<center><h1>Lessons</h1></center>
{menus.map((menu) => (
<li><Link to="{{menu.lessonContent}}">{menu.lessonName}</Link></li>
))}
<Switch>
<Route path="/:id" children={<Child />} />
</Switch>
</div>
</Router>
)
};
function Child() {
// We can use the `useParams` hook here to access
// the dynamic pieces of the URL.
let { id } = useParams();
return (
<div>
<h3>ID: {id}</h3> //content should show up here
</div>
);
}
export default Menus
Is there a way to bind a state element to the route so a different portion of the json response will be passed instead of a route? Can I use a key and somehow combine it with an element?
Here is what the link was originally:
<li><Link to="/route">{menu.lessonName}</Link></li>
and here is what I need it to be:
<li><Link to="{{menu.lessonContent}}">{menu.lessonName}</Link></li>
If I understand correctly what you are trying achieve, I think your Menus component should look more like this:
Menus.js
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useParams
} from "react-router-dom";
const Menus = ({ menus }) => {
return (
<Router>
<div>
<center>
<h1>Lessons</h1>
</center>
{menus.map(menu => (
<li key={menu.id}>
<Link to={`/${menu.id}`}>{menu.lessonName}</Link>
</li>
))}
<Switch>
{menus.map(menu => (
<Route
key={menu.id}
path="/:id"
children={<Child content={menu.content} />}
/>
))}
</Switch>
</div>
</Router>
);
};
function Child({ content }) {
let { id } = useParams();
return (
<div>
<h3>ID: {id}</h3>
<div>{content}</div>
</div>
);
}
export default Menus;
Here are some of the things I fixed here:
On your example you were passing a string instead of an object key to the to prop: to="{{menu.lessonContent}}" instead of to={menu.lessonContent}
I'm mapping over menus in order to dynamically create the Route components and their corresponding paths.
I'm passing menu.content as a prop to the Child component.
I added keys to every rendered element which is a result of iteration.

How to redirect to home page on browser refresh in reactjs?

I am building an application with reactjs, react-router-dom and redux (for state management). The application has multiple pages including home, phoneRepair and phoneSelection pages. The user navigates to these above pages and I store their inputs. Hence while the user refresh the page (either by f5 or by pressing button on browser) I want them to redirect to home page.
I have searched for the answer on google and stack overflow.
Some of the posts requested to use IndexRoute - but i think it is deprecated.
I have checked the below answer on stackoverflow but it didn't help.
redirect to an another web page on browser refresh
my code of App.js
import { BrowserRouter, Switch, Route } from "react-router-dom";
import Navbar from "./components/layout/Navbar";
import Main from "./components/Main/Main";
import PhoneRepair from "./components/Floating/PhoneRepair";
import PhoneSelection from "./components/Floating/PhoneSelection";
import PhoneColorSelection from "./components/Floating/PhoneColorSelection";
class App extends Component {
render() {
return (
<BrowserRouter>
<div className="App">
<Navbar />
<Switch>
<Route exact path="/" component={Main} />
<Route path="/phoneRepair/:brand/:color" component={PhoneColorSelection} />
<Route path="/phoneRepair/:brand" component={PhoneSelection} />
<Route path="/phoneRepair" component={PhoneRepair} />
{/* <Route path='/signin' component={SignIn} /> */}
{/* <Route path='/signup' component={SignUp} /> */}
{/* <Route path='/create' component={CreateProject} /> */}
</Switch>
</div>
</BrowserRouter>
);
}
}
export default App;
My code of one of the page "Page Selection" is
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createModel } from "../../store/actions/createDetails";
class PhoneSelection extends Component {
constructor(props){
super(props)
this.phoneModel = [];
this.handleClick = this.handleClick.bind(this);
}
handleClick = e => {
const model = this.phoneModel[e].textContent;
console.log(this.phoneModel);
this.props.createModel(model)
};
render() {
return (
<div className="conatiner">
<div>This is the list of phones of company previously selected.</div>
<div className="details">
{this.props.companyName.phoneReducers.project.map((phone) => {
if (phone.id === this.props.match.params.brand) {
return phone.phones.map((p,key) => (
<Link to={`/phoneRepair/${phone.id}/${p.alias}`} key={key} onClick={() => this.handleClick(key)}>
<div className="details-phoneRepair" ref={ref => {this.phoneModel[key] = ref}}>{p.phoneName}</div>
</Link>
));
}
})}
</div>
</div>
);
}
}
const mapStatetoProps = state => {
return {
companyName: state
};
};
const mapDispatchToProps = dispatch => {
return {
createModel: details => dispatch(createModel(details))
};
};
export default connect(mapStatetoProps, mapDispatchToProps)(PhoneSelection);
When user refreshes the page from "phone selection" page I want them to redirect to home page. However currently when user refreshes it stays to same page. Thanks

Pass props to React component dependent on route

I have a root component which uses react-router:
<HashRouter>
<aside>
<Sidebar />
</aside>
<main>
<Switch>
{/* -- routes go here -- */}
</Switch>
</main>
</HashRouter>
I want my Sidebar component to have different content depending on which route we're on. So if I have two routes, foo and bar, when I go to /foo I want Sidebar to have different props than when I visit /bar. I've tried passing the location as a prop:
<Sidebar location={this.context.router.location.pathname} />
But I'm pretty sure that's not how it works... And sure enough it didn't work.
You can use withRouter to pass values from route to another component. This way you can do conditional rendering or implement any other logic related to the current route to your component.
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 }.
Example (from official documentation)
// A simple component that shows the pathname of the current location
class ShowTheLocation extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
}
render() {
const { match, location, history } = this.props
return (
<div>You are now at {location.pathname}</div>
)
}
}
// Create a new component that is "connected" (to borrow redux
// terminology) to the router.
const ShowTheLocationWithRouter = withRouter(ShowTheLocation)
Here's a method using React Router's withRouter to 'connect' the <Sidebar /> component to the router.
With withRouter we create our <Sidebar /> component as normal, then 'connect' it like this:
//Sidebar
class Sidebar extends React.Component {
render() {
const { location } = this.props;
return (
<div>
<h1>Sidebar</h1>
<p>You are now at {this.props.location.pathname}</p>
</div>
)
}
}
const SidebarWithRouter = withRouter(Sidebar);
In the end we have a new <SidebarWithRouter /> component connected to the router so it has access to match, location, and history.
Unfortunately the code snippet won't work in Stackoverflow due to the history within the iframe, but here's the code, and a working Codepen.
let { BrowserRouter, Link, Route } = ReactRouterDOM;
let { Switch, withRouter } = ReactRouter;
let Router = BrowserRouter;
// App
class App extends React.Component {
render() {
return (
<Router>
<div className="container">
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
<hr />
<aside>
<SidebarWithRouter />
</aside>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</Switch>
</div>
</Router>
);
}
}
//Home
const Home = () => (
<div>
<h1>Home</h1>
<p>This is the Home Page.</p>
</div>
);
//About
const About = () => (
<div>
<h1>About</h1>
<p>This is about</p>
</div>
);
//Sidebar
class Sidebar extends React.Component {
render() {
const { location } = this.props;
return (
<div>
<h1>Sidebar</h1>
<p>You are now at {this.props.location.pathname}</p>
</div>
)
}
}
const SidebarWithRouter = withRouter(Sidebar);
ReactDOM.render(<App />, document.getElementById("app"));

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