I have a signup page signup.js after successful sign in I need to take those data to another route view sign in details page if I render sign in details then I am viewing it in the same page how to take it to another route ??If I do through window.name after refresh I couldn't view the data[my page layout]
1st page
class Validation extends Component {
constructor(props) {
super(props);
this.validate = this.validate.bind(this);
}
validate(detail,number) {
//i need to take this number to view page
});
}
render() {
return (
<div>
<SignupForm onAddDetail={this.validate} />
</div>);
}
}
export default Validation;
2nd page
class DetailsComponent extends Component {
render() {
let DetailNodes = this.props.details.map(detail =>
(
<Register key={detail.id}
emailId={detail.emailId} password={detail.password}
firstName={detail.firstName} lastName={detail.lastName}
location={detail.location} mobileNumber={detail.mobileNumber}>
</Register>
)
);
return (
<div> <br></br><br></br><br></br><br></br>
{DetailNodes[number-1]}//I need that number from 1st page and carried here
<br/>
</div>);
}
}
route.js
my route page
<Route path="/signup" component={Validation}/>
<Route path="/view" component={DetailsComponent} />
As option you can do it like this:
add field to state
success: true | false
and if signup is successfull
setState({success: true})
and in signup component add ternary
import {Redirect} from 'react-router-dom';
!success ? <SignUp /> : <Redirect to={{
pathname: '/view',
state: {data: signUpCredentials}
}}
/>
and in View component you can access it in
{props.location.state}
You can use the useHistory() hook of React router.
For eg:
const history = useHistory();
...
history.push('/');
You can pass props from Route render. You can do this in multiple ways. If your data is available at router level. Like below. Or setup up a Store for shared data
const myProps = {x,y,z}
<Route path="/signup" render={()=> <Validation myNewProp='someprop' />} />
<Route path="/view" render={()=> <DetailsComponent {...myProps} />} />
Related
I am working on shifting react js to next js, i am facing some issue in react router, supposed i have many dashboard route and those route must be pass though login , so i have to pass all the dashboard route though login, if user is not login than redirect to login route.
my react RouteWithAuthLayout
const RouteWithAuthLayout = props => {
const { layout: Layout, component: Component, ...rest } = props;
return (
<Route
{...rest}
render={matchProps => {
if (!loggedIn()) {
return (
<Redirect
to={{
pathname: "/auth/login",
search: "?next="+window.location.pathname
}}
/>
)
}
return (
<Layout>
<Component {...matchProps} />
</Layout>
)
}}
/>
);
};
and my Dashboard.js is look like this
<Switch>
<RouteWithAuthLayout
component={BuyShipProductDetail}
layout={DashboardLayout}
exact
path="/dashboard/buy-ship-for-me/product/:productNumber/detail"
/>
</Switch>
and my Router.js
<Route path="/dashboard">
<Dashboard />
</Route>
is there any function of class to convert my react router to next router ?
I'm trying to render a print page using React Router. So I have two components:
export default class PurchaseOrder extends React.Component{
....
render(){
const {orderDate, client} = this.state.order;
//omitted for brevity
return(
<BrowserRoute>
<Button
component={Link}
to="/order/print"
target="_blank"
>
Print
</Button>
<Route
path="/order/print"
render={props => (
<OrderPrint
{...props}
orderDate={orderDate}
client={client}
/>
)}
/>
</BrowserRoute>
}
}
And the OrderPrint:
export default function OrderPrint(props) {
return (
<div>props.orderDate</div>
<div>props.client.name</div>
);
}
As you can see, I'm trying to present the printable version of the purchase order with a click of a button. The OrderPrint component gets rendered, but it's rendered right below the button. I could put the Route inside my root component, which is App, that way making sure that I get only the contents of the OrderPrint component rendered like this:
class App extends Component {
render() {
return (
<div className="App">
<Router>
<Route exact path="/" component={PurchaseOrder} />
<Route exact path="/order/print" component={OrderPrint} />
</Router>
</div>
);
}
}
But in that case, I won't be able to pass the necessary props to it. So in this particular case, how to replace entire page content with the contents of OrderPrint component and still be able to pass the necessary input to it?
Update
As #Akalanka Weerasooriya mentioned in comments, I could have the entire state kept in the App component. But one thing stopped me from doing this: This means I'll practically always have to use the render prop of the Route component, instead of the component prop. Ok, that's not a problem, but if it's the way to go, then why does React Router documentation almost always use the
<Route path="/about" component={About} />
pattern as the standard way of using it? So to recap it, if I go the Single Source of Truth way and store all my state in one place, then doesn't it mean that I will always use
<Route path="/about" render={props=>(<div>props.someProp</div>)} />
I don't say there's a problem with it, it's just mentioning it in the documentation only after component={SomeComponent} pattern confuses me.
Not sure why you need a different route for a print page, but anyway if you want it on a new empty page, you can take advantage of the ReactDOM.createPortal feature.
You can create a new page and or even a new window using window.open while keeping the flow of react data in sync.
Here is a running example of a portal on a new window with live state updates from the component that triggered this window using a portal:
running example, i'm sharing an external snippet and not using stack-snippets here because window.open returns null in the contexts of stack-snippets
Source code:
class WindowPortal extends React.PureComponent {
containerEl = document.createElement("div");
externalWindow = null;
componentDidMount() {
const { width = 450, height = 250, left = 150, top = 150 } = this.props;
const windowFetures = `width=${width},height=${height},left=${left},top=${top}`;
this.externalWindow = window.open("", "", windowFetures);
this.externalWindow.document.body.appendChild(this.containerEl);
}
componentWillUnmount() {
this.externalWindow.close();
}
render() {
return ReactDOM.createPortal(this.props.children, this.containerEl);
}
}
class App extends React.PureComponent {
state = {
counter: 0,
showWindowPortal: false
};
componentDidMount() {
window.setInterval(() => {
this.setState(state => ({
counter: state.counter + 1
}));
}, 1000);
}
toggleWindowPortal = () => {
this.setState(state => ({
...state,
showWindowPortal: !state.showWindowPortal
}));
};
closeWindowPortal = () => {
this.setState({ showWindowPortal: false });
};
render() {
return (
<div>
<h1>Counter: {this.state.counter}</h1>
<button onClick={this.toggleWindowPortal}>
{this.state.showWindowPortal ? "Close the" : "Open a"} Portal
</button>
{this.state.showWindowPortal && (
<WindowPortal closeWindowPortal={this.closeWindowPortal}>
<h2>We are in a portal on a new window</h2>
<h3>{`This is the current state: ${this.state.counter}`}</h3>
<p>different window but sharing the state!!</p>
<button onClick={() => this.closeWindowPortal()}>Close me!</button>
</WindowPortal>
)}
</div>
);
}
}
here you have a PrivateRoute which is a custom route which holds a header and header is rendered in PrivateRoute routes only so when you try to navigate to new route like path="/order/print" then you won't get header which has button in it.
function Header(props) {
return (
<div>
<Button
component={Link}
to="/order/print"
target="_blank">
Print</Button>
{props.children}
</div>
)
}
const PrivateRoute = ({ component: Component, layout: Layout, ...rest }) => {
return <Route {...rest} render={props => {
return <Layout>
<Component {...props} />
</Layout>
}} />
}
export default class PurchaseOrder extends React.Component{
render(){
const {orderDate, client} = this.state.order;
//omitted for brevity
return(
<BrowserRouter>
<div>
<PrivateRoute exact path="/" layout={Header} component={Landing} />
<Route
path="/order/print"
render={props => (
<OrderPrint
{...props}
orderDate={orderDate}
client={client}
/>
)}
/>
</div>
</BrowserRouter>
}
}
I have an application, where I map some sample user components. I add some props, and I want to make a conditional nav link, that renders just a simple "profile components that show the name.
So far I have made a conditional nav, link inside the component, and the props get send correctly, and it displays the paragraph under my User component, but I want to make it redirect, so it only shows the Profile component.
Is there a way so it only shows that component. I tried with the switch but I realized, that it only renders the first, route, so everything else, will still be shown...
render() {
let persons= this.state.persons.map((item, index) =>{
return(
<Router>
<User key={index} name={item.name} img={item.img} id={item.id} />
</Router>
)
})
//user component
render(){
console.log(this.props.name)
return(
<Switch>
<div >
<img src={this.props.img} alt="profile" style={{float: 'left'}}>
</img>
<p style={{textAlign: 'center'}}>{this.props.name}</p>
<p>It's here={this.props.loggedInProp}</p>
<Route path="/:username" exact component={ Profile} />
<NavLink to={`/${this.props.name}`}>Click me</NavLink>
</div>
</Switch>
//Profile component
const Profile= ({match}) =>{
return(
<div>
<p>Hello {match.params.username}</p>
</div>
)
}
<Route
exact
path="/profile/view/:username"
render={props => <ProfileView {...props} />}
/>
inside of ProfileView component you could then use this.props.match.params.username to filter your collection of data and display only it's details.
ProfileView component
import React, { Component } from 'react';
export class ProfileView extends Component {
constructor(){
super()
this.state = {
allUsers[{ user1 ... }, {user2 ...}, ...],
selectedUser: {}
}
}
componentDidMount(){
// fetch('/get/users/from/somewhere').then(users => {
// this.setState({allUsers: users}) // Usually you would just pull your one user from the route and then fetch it's single details from a database
// })
this.setState({selectedUser: allUsers.filter(user => user.username === this.props.match.params.username)})
}
render() {
return (
<div>
<em>Do stuff with your this.state.selectedUser... things here</em>
</div>
);
}
}
I'm having some problems with implementing PrivateRoute in React. Here is my code:
class App extends Component {
constructor(props) {
super(props);
this.state = {
currentUser: null,
loadingUser: true
}
}
componentDidMount() {
this.onAuth();
};
onAuth = () => {
getCurrentUser().then((json) => {
console.log(json);
this.setState({
currentUser: json,
loadingUser: false
})
}).catch((error) => {
this.setState({
currentUser: null,
loadingUser: false,
})
})
};
logout = () => {
logout();
this.setState({
currentUser: null,
loadingUser: false
});
this.props.history.push("/");
toast.info("Succesfully logout.");
};
render() {
return (
<div className="body">
<ToastContainer closeOnClick={false}/>
<ApplicationHeader currentUser={this.state.currentUser} logout={this.logout}/>
<Grid>
<div className="app-content">
<Switch>
<Route exact path="/vote/:id" render={(props) => <Vote currentUser={this.state.currentUser} {...props}/>}/>
<Route exact path="/login" render={() => <Login onAuth={this.onAuth} />}/>
<PrivateRoute authed={this.state.currentUser != null} exact path="/vote" component={NewProcess} />
<PrivateRoute authed={this.state.currentUser != null} exact path="/items" component={NewItems} />
<Route component={NotFound}/>
</Switch>
</div>
</Grid>
<Footer/>
</div>
);
}
}
const PrivateRoute = ({component: Component, authed, ...rest}) => {
return (
<Route
{...rest}
render={(props) => authed === true
? <Component {...props} />
: <Redirect to={{pathname: '/login', state: {from: props.location}}} />} />
)
}
When user posts credentials (or App main component gets rendered) onAuth method gets invoked and sets (or not) currentUser property of App's state. This property is null (when user is not authenticated) and represents userdetails such like id and username (when user is authenticated). Then, in PrivateRoute based on that property component gets rendered or application redirects user back to the login page. And that doesn't work well. I mean when i'm already authenticated and try to access any of private route, i am redirected to proper component. Problem occurs in 2 situations:
right after logging in - application doesnt redirect me to component
i want to access, insted i stay on the login page.
refreshing page (in browser) corresponded to private route.
It seems like PrivateRoute component doesnt get refreshed when currentUser property gets changed, which is kinda weird because i'm using similar approach in ApplicationHeader to display username when user is authenticated (and that is refreshed correctly).
So, what am i doing wrong here?
I did it rendering the route or the redirect depending on the condition and it worked for me.
Something like the following:
class PrivateRouteComponent extends React.Component{
render(){
return (
this.props.isAuthenticated===true?
(
<Route path={this.props.path} render={this.props.component} />
):
(<Redirect to={{
pathname: '/login',
state: { from: this.props.path }
}} />));
}
}
I have a component tree like this:
-App
--UserList
---UserItem
---UserItem
---UserItem
--User
I'm not being able to pass user data from UserItem to User. This is what I have:
App.js
export default class App extends Component {
state = { users: [] }
componentDidMount() {// fetch and setState}
render() {
return (
<BrowserRouter>
<Route
exact
path="/"
render={() => <UserList users={this.state.users} />}
/>
</BrowserRouter>
)
}
}
UserList.js
export default function({ users }) {
return (
<div>
{users.map(user => (
<UserItem user={user} key={`${user.id}`} />
))}
</div>
)
}
This is where the problem is: I want to pass the data from the parent component to the child User component, instead of having to fetch the user data from the API again.
UserItem.js
export default function({ user }) {
return (
<div>
<Link to="/user">{user.name}</Link>
<Route path={`/user/${user.name}`} render={() => <User user={user} />} />
</div>
)
}
I'm not sure what you're trying to implement here. Your app renders the UserList when then route is /. The UserList renders a UserItem component for each user in the array. Each UserItem simply renders a route specific to every user, which will render the User component if that route is triggered.
But if I'm not mistaken, the UserList will not be rendered if the route is anything but /, so if someone accesses user/..., the inner routes won't actually exist.
Essentially, this app will not render anything.
If you remove the exact keyword from the route in App, I think you'll get the result you are looking for. In this case, opening /user/<USER_NAME> will render the User element for that user.
Your question is regarding passing props into a component through a route, and the mechanism you've used is correct.
<Route path={...} render={() => <User user={user} />} />
This is actually right. See the code linked below. On changing the route to /user/User1, you'll see the name of "User1" rendered in the app.
See the working code here: https://codesandbox.io/s/18w3393767
You should use this.props.users in the UserItem component
i'm not sure but could you pass props like below, here i pass props to render and then to User Component
<Route path={`/user/${user.name}`} render={(props) => <User user={user} {...props} />} />
export default function({ users }) {
return (
<div>
{ this.props.users.map(user => (
//mistake here this.props.users.map not users.map
<UserItem user={user} key={`${user.id}`} />
))}
</div>
)
}