Passing Routeing related props to component not rendered by <Route> - javascript

i have a Dashboard Component:
class DashboardPage extends Component {
....
render() {
const currentLocationPath = this.props.location.pathname;
const isAuthenticated = true;
// redirecting to /dashboard/main and saving current state to next path by pushing it to history object
if (currentLocationPath === '/dashboard/' || currentLocationPath === '/dashboard') {
this.props.history.push('/dashboard/main');
}
const { match } = this.props;
if (isAuthenticated) {
return (
<div className="DashboardPage d-flex flex-column flex-grow">
{/* email confirmation message for loggedin user to verify email ID*/}
{!this.state.isEmailVerified ? <div className="email-confirmation">
<span className="email-confirmation__desktop">
Please check your inbox to confirm your email <strong>{'loggedin user\'s email'}</strong>.
Didn’t receive an email? </span>
<span className="email-confirmation__mobile">Confirm your email. </span>
<a className="js-resend-email" href="#" onClick={this.resendMail}>Resend</a>
</div> : null}
<div className="DasboardPageMain d-flex flex-grow">
{/* sidebar with slide-in effect from left on toggle */}
<SidebarMenu currentLocationPath={currentLocationPath} channels={this.state.channels} />
<div className="DashboardPage__overlay" />
<main className="DashboardPage__Content d-flex flex-grow">
{/* swapping DashboardPage's Child Components based on current url set by <Router/> */}
<Route path="/dashboard/main" render={() => <Dashboard toggleModal={this.toggleModal} />} />
<Route path="/dashboard/channels/:id/:channelName" component={VideoStats} />
<Route path="/dashboard/edit_video" component={EditVideo} />
<Route path="/dashboard/account" component={Account} />
<Route path="/dashboard/socialMedia" component={SocialMedia} />
<Route path="/dashboard/media-library" component={MediaLibrary} />
<Route path="/dashboard/shares" component={Shares} />
{/* <Route path="/dashboard/platform/:data" component={Platforms} /> */}
{/* <Route exact path="/dashboard/channels/:id/:channelName" component={VideosList} /> */}
</main>
{/* Modal With Nested Form to add Chaanel's info. */}
<Modal className="addChannelModal" isOpen={this.state.modal} toggle={this.toggleModal} >
<ModalBody>
<AddChannelForm toggleModal={this.toggleModal} notifySuccess={this.notifySuccess} notifyError={this.notifyError} />
</ModalBody>
</Modal>
</div>
<Footer />
{/* React toastify for toast notifications */}
<ToastContainer
className={{ textAlign: 'center' }}
progressClassName={css({ background: '#007aff' })} />
</div>
);
} else {
return <Redirect to={'/'} />;
}
}
}
export default withRouter(DashboardPage);
Now i want to access the router url params inside <SidebarMenu> component but inside <SidebarMenu> console.log(this.props.match.params) is showing empty object.
But if i do console.log(this.props.match.params) inside any of components being rendered by <Route/> for example:
<Route path="/dashboard/account" component={Account} />
I easily get all params in url.
Is there way to access all these router related props in <SidebarMenu>
?
currently i am conditionally rendering JSX inside <SidebarMenu> like so:
const currentLocationPath = this.props.currentLocationPath;
const pathArray = window.location.pathname.split('/');
{ pathArray.length > 3 &&
<Media tag="li" className={`${pathArray.length === 3 ? 'li-active' : null} li-channels align-items-center mb-1 py-1`}>
{/* Chevron Icon */}
<Media left middle tag="span" className="media-chevron-right ml-5 mr-1">
<FontAwesomeIcon size="xs" icon={currentLocationPath == '/dashboard/main' ? faChevronRight : faChevronDown} className="" />
</Media>
{/* channel's main body */}
<Media body className="text-center text-sm-left mb-3 mb-sm-0">
<Media heading tag="h6" className="m-0">
Channels
</Media>
</Media>
</Media> }

You are not passing match to <SidebarMenu> inside <DashboardPage> render.
You could either pass it as a prop inside your DashboardPage render:
<SidebarMenu match={match} currentLocationPath={currentLocationPath} channels={this.state.channels} />
Or wrap it with withRouter.

Try passing props like this in component
<Route path="/dashboard/account" render={ (props) => <Account {...props} /> }/>

Related

React Router v6 render component on same page

I'm trying to change some "state varibale" managed component rendering into react-routing.I am using react-router 6.3.
This is the App.js
function App() {
return (
<Router>
<Header />
<Selections />
<Routes>
<Route path='/:type' element={<PostMain />}>
<Route path=':comments' index element={<Comments />} />
</Route>
</Routes>
</Router>
);
}
This is the Component
const handleLoadComments = () => {
if (!comments) {
dispatch(loadCommentsByPost(props.permalink));
} else {
navigate(-1);
//navigate(`/${type}`)
//console.log(type);
}
}
return (
<div className="Post">npm
<div className='Post-header' >
<p>Subbreddit: {props.subreddit_name_prefixed}</p>
<p>{created(props.created_utc)}</p>
</div>
<Media post={props} />
<div className='Post-footer-container' >
<div className='Post-footer' >
<div className='Post-footer-votes'>
<img src={upVote} alt="upvote" />
<p style={{color: "green"}} > {props.ups} -</p>
<img src={downVote} alt='downvote' />
<p style={{color: "red"}} > {props.downs}</p>
</div>
<Link to={`${props.id}`} >
<div className='Post-footer-comments' onClick={handleLoadComments} >
<input type="image" className='Comments-image' src={commentImg} alt='comment bubble' />
<p>{props.num_comments}</p>
</div>
</Link>
</div>
{/* { loading && <div className='Loading-container' ><img src={Loading} alt='loading' className='Comment-loading' /></div>} */}
</div>
<Outlet />
{/* {comments && <Comments comments={comments} />} */}
</div>
);
}
My goal would be to render the comments under the post, i did it with local state and setState before but is there a way to do it with routing?
I can see the change in the url when i click on a comment, i tried "navigate(/${type})" but not even the url changed so i used "navigate(-1)"
But the Comments component doesn't render!
Thanks in Advance!
Try to remove the path from the comments route since it's the index it sould be there by default
function App() {
return (
<Router>
<Header />
<Selections />
<Routes>
<Route path='/:type' element={<PostMain />}>
{/* <Route path=':comments' index element={<Comments />} /> */}
<Route index element={<Comments />} />
</Route>
</Routes>
</Router>
);
}
in your current approach you need to navigate to /type/comments, but it should be just /type

React Router Shows Blank Page When Using <Link>

After updated a bunch of our dependencies we are now are forced to use anchor tags which causes redirects, before we used but now everytime we click on a it goes to the proper url ie /screens but is just a blank page and never presents the components, below is our parent index.tsx file:
ReactDOM.render(
<Provider {...stores}>
{/* Changed routes to children */}
{/* <Router children={routes} history={createHistory} /> */}
<Router history={createHistory}>
<div>
<Switch>
<Route path='/oauth2callback' componentDidMount={console.log()}>
{() => {
if(window.location.href.includes('/oauth2callback'))
{
oauth2callback(window.location.hash)
}
}}
</Route>
<Route path='/testing' component={Get} />
<Route path='/'>
{/* Function that determines if the user is logged in and can allow the authenticated passage or not. If no, it will not render authenticated pages*/}
{() => {
if(auth.loggedIn())
{
console.log("is logged in")
return(
<div>
<Route component={App} history={createHistory}/>
<div className="row" id="wrapper">
<Switch>
{/* <Route path='/screens' component={Screens}/> */}
<Route path='/screens' component={Screens}/>
<Route path='/playlists' component={Playlists}/>
<Route path='/content' component={Content}/>
<Route path='/help' component={HelpNav}/>
<Route component={NotFound}/>
</Switch>
</div>
</div>
)
}
else
{
console.log("is not logged in")
return(
<Route path='/' component={HomeNav}/>
)
}
}}
</Route>
<Route path='401' component={Get} />
</Switch>
</div>
</Router>
</Provider>,
and here is the app.tsx with the navbar:
<Nav className="mb-nav">
{/* <IndexLinkContainer to="/screens"> */}
<Nav.Item style={{width: widthConstants[0]}}>
<Link to='/screens' style={{color: this.state.navIndex === 0 ? "white" : "bbddba"}}>
Screens
</Link>
</Nav.Item>
{/* </IndexLinkContainer> */}
{/* <LinkContainer to="/playlists"> */}
<Nav.Item style={{width: widthConstants[1]}}>
<a href="/playlists" style={{color: this.state.navIndex === 1 ? "white" : "bbddba"}}>
Playlists
</a>
</Nav.Item>
{/* </LinkContainer> */}
{/* <LinkContainer to="/content"> */}
<Nav.Item style={{width: widthConstants[2]}}>
<a href="/content" style={{color: this.state.navIndex === 2 ? "white" : "bbddba"}}>
Content
</a>
</Nav.Item>
{/* </LinkContainer> */}
{/* <LinkContainer to="/help"> */}
<Nav.Item style={{width: widthConstants[3]}}>
<a href="/help" style={{color: this.state.navIndex === 3 ? "white" : "bbddba"}}>
Help
</a>
</Nav.Item>
{/* </LinkContainer> */}
{this.shouldRenderTouch && <TouchButton/>}
</Nav>
</Navbar.Collapse>
</div>
</Navbar>
any idea what is different in the new react router update to cause this bug to exist?
The fix was much simpler than I thought, the new update integrated BrowserRouter instead of the Router so I replaced
<Router history={createHistory}>
with
<BrowserRouter>
and everything is now working as it should
Read "Routes and Links are relative to their parent" on this React Router 6 article
https://medium.com/frontend-digest/whats-new-in-react-router-6-732b06cc83e4
by the way it's strange that you have <a> tags instead of Link components sometimes

Why is my route not loading my React component?

I'm using react-router in my app for routing, where all of my routes work apart from the last one which is being used for modal purposes, however it's not loading the component.
function App() {
return (
<BrowserRouter basename="/veochorusapp">
<ModalSwitch />
</BrowserRouter>
);
}
export default App;
function ModalSwitch() {
let location = useLocation();
let background = location.state && location.state.background;
return (
<div className="App">
<Switch location={background || location}>
<Route exact path="/" component={Home} />
<Route path="/applications" component={Applications} />
<Route path="/waterType" component={WaterType} />
<Route path="/feedType" component={FeedType} />
<Route path="/products/:productName" component={Product} />
<Route path="/products" component={Products} />
<Route path="/interactive" component={ProductView} />
</Switch>
{background && <Route path="/feature/:id" children={<Modal />} />}
{background && <Route path="/accessory/:id" children={<AccessoryModal />} />}
</div>
);
}
The route that is not loading the component is the following:
{background && <Route path="/accessory/:id" children={<AccessoryModal />} />}
The code that links to this route is as below. I have used the same process on a previous component which works perfectly.
function AccessoryBtns() {
let location = useLocation();
return (
<ul className="accessoryBtns">
{AccessoriesData.map((i, index) => (
<li key={index}>
<Link
key={i.id}
className="btn"
to={{
pathname: `/accessory/${i.id}`,
state: { background: location }
}}
>
{i.name}
</Link>
</li>
))}
</ul>
)
}
export function AccessoryModal() {
let history = useHistory();
let { id } = useParams();
let accessory = AccessoriesData[parseInt(id, 10)];
if (!accessory) return null;
let back = e => {
e.stopPropagation();
history.goBack();
};
return (
<div className="modal">
<div className="row">
<div className="col-md-6 text-right">
Image
</div>
<div className="col-md-6">
<h2>{accessory.name}</h2>
<p>{accessory.description}</p>
</div>
</div>
<div className="backBtn" onClick={back}><FontAwesomeIcon icon={faArrowLeft} /></div>
</div>
);
}
First, it looks they are not inside <Switch>. Second, according to router docs, children must be a function
{background && <Route path="/feature/:id" children={() => <Modal />} />}
But since you pass no props to Modal you can simply use
{background && <Route path="/feature/:id">
<Modal />
</Route>}
or
{background && <Route path="/feature/:id" component={Modal} />}

React-router: change in url but not in components displayed

I have a problem with react-router. This is my /home component, the first page you see after logging in:
return(
<>
<CustomNavbar />
<Container fluid>
{ loading ? (
<div>Loading...</div>
) : (
<Router>
<ProtectedRoute
path='/home/mem'
render={(props) => <MResult
{...props}
data={data}
users={users} />
}
/>
<ProtectedRoute
path='/home/reading'
render={(props) => <RResult
{...props}
data={readingData}
users={users} />
}
/>
</Router>
)}
</Container>
</>
)
I have a table and I need to display different data based on the second part of the url (I'm using my own component ProtectedRoute to check for authentication, but the behaviour is the same we the usual Route component).
In the CustomNavbar component I have two links:
return(
<Navbar bg="primary" variant="dark">
<Navbar.Brand className='cursor-default'>
<span style={{marginLeft: "10px"}}></span>
</Navbar.Brand>
<Navbar.Toggle />
<Navbar.Collapse>
{ props.authenticated && (
<>
<Button>
<Link to="/home/reading">Reading</Link>
</Button>
<Button>
<Link to="/home/mem">MemResult</Link>
</Button>
</>
)}
</Navbar.Collapse>
<Navbar.Collapse className='justify-content-end'>
{ props.authenticated && (
<Button onClick={logout}>logout</Button>
)}
</Navbar.Collapse>
</Navbar>
)
The problem is that if I click on the links in the navbar I can see the url changing accordingly, but the new component is not being loaded, I still see the previous one. If I hit the browser's refresh button, then the correct component is loaded, but once that happened, again, clicking on the links won't change a thing but the url.
How can I fix this?
The CustomNavbar component is outside of the Router provider which is why Links aren't able to communicate to the Route component.
The solution is to render Router component at the top level and render CustomNavbar as a default route
return(
<Router>
<Route component={CustomNavbar} />
<Container fluid>
{ loading ? (
<div>Loading...</div>
) : (
<ProtectedRoute
path='/home/mem'
render={(props) => <MResult
{...props}
data={data}
users={users} />
}
/>
<ProtectedRoute
path='/home/reading'
render={(props) => <RResult
{...props}
data={readingData}
users={users} />
}
/>
</Router>
)}
</Container>
</Router>
)

React Router Access Object Details

I'm trying to display the details of a clickable object on a new page. I've tried a few examples from React Router Pass Param to Component with limited success.
The only one that "kind of" worked was Alexander Luna's suggestion to access via ID in component. However, while this returns the id number, I can't access any other values, like "title".
I have tried globalStore, however, the error message told me that it isn't defined. I'm not sure that's my best option or not.
Ultimately I want the whole object back as I plan to use context with See 'D' below.
App) I have commented out my previous attempts
class App extends Component {
render() {
return (
<React.Fragment>
<Navbar />
<Switch>
<Route exact path="/" component={ProductList} />
<Route path="/cart" component={Cart} />
<Route exact path="/details/:id" component={Details} />
{/* <Route exact path="/details/:id" render={(props) => <Details globalStore={globalStore}
{...props} /> } /> */}
{/* <Route exact path="/details/:id" render={(props)=>{ <Details id={props.match.params.id}/>}}
/> */}
<Route component={Default} />
Details page I want to render in.
import React, { Component } from "react";
export default class Details extends Component {
render() {
return(
<div>
<h2>{this.props.match.params.id}</h2>
<h2>{this.props.match.params.title}</h2>
</div>
The product page, I'm using this link to click through to details.
xport default class Product extends Component {
render() {
const { id, title, img, price, inCart } = this.props.product;
return (
<ProductWrapper className="col-9 mx-auto col-md-6 col-lg-3 my-3">
<div className="card">
<div className="img-container" onClick={() => console.log('you clicked container')}
>
<Link to={`/details/${ this.props.product.id }`} >
<img src={img} alt="product" className="card-img-top" />
</Link>
D - This is how the original code looked, I want to use the {title} tags but I don't know if I need "value => " etc.
<ProductConsumer>
{value => {
const {
id,
company,
img,
info,
price,
title,
size,
} = value.Product;
return (
<div className="container py-5">
{/* title */}
<div className="row">
<div className="col-10 mx-auto text-center text-slanted text-blue my-5">
<h1>{title}</h1>
</div>
</div>
You need an extra parameter
<Route exact path="/details/:id/:title" component={Details} />
export default class Details extends Component {
render() {
return(
<div>
<h2>{this.props.match.params.id}</h2>
<h2>{this.props.match.params.title}</h2>
</div>
);
}
}
// In Product component
<Link to={`/details/${ this.props.product.id }/${this.props.product.title}`} >
<img src={img} alt="product" className="card-img-top" />
</Link>
Try to read the params in the constructor like this:
constructor(props)
{
super(props)
const { match: { params } } = this.props;
var id = params.id
this.state = {
id : id,
}
}
and then read the id from the state.
If you want to pass the whole object you can send it through the url in base64 like this :
<Link to={`/details/+btoa( this.props.product )} >
<img src={img} alt="product" className="card-img-top" />
</Link>
And recieving it in the constructor like the previous snippet en parse it to string with the function atob() and then to json.

Categories