React: Passing Props from grandparent to grandchild - javascript

I have a problem with passing props in react. This is my folder structure:
src
Component
Button.js
Container
PageContainer.js
Page
Page.js
I am using Bootstrap 4 to create a Button within Button.js:
<div>
<a className="btn btn-primary sharp" href={this.props.url} role="button">{this.props.btnName}</a>
</div>
There is nothing else in the class Button. So now I put a Button into the class PageContainer:
<div>
<Header/>
<Button url={this.props.urlBack} btnName="Back"/>
<Button url={this.props.urlNext} btnName="Next"/>
</div>
As you can see I passed a title to the buttons: Back and Next. That works fine. I could now add an url and it would work fine, but that's not what I want.
I added the PageContainer to the class Page such that I can add an url at this level:
<div>
<PageContainer urlBack="/" urlNext="/nextPage"/>
</div>
For some reason this is not working. Can someone explain me how I can pass props from grandparent to grandchild? In the documentation it says that this is the way how to do it. I also get no error, because the prop is not passed from Page to PageContainer. A console.log(this.props.urlBack) results in undefined.
PS: Maybe you asking why I am using the Page.js or for what reason do I have the PageContainer. First: There are far more components, I just left them out. Second: I wanna reuse the PageContainer for several pages such that I just have to change the url.

It doesn't look like you are passing props to your <VideoContainer /> component. You are merely assigning it as a routed component <Route />
Your answer can be found here:
React react-router-dom pass props to component
i.e.
<Route path="/algorithmus/bubblesort/video"
render={(props) => <VideoContainer {...props} />}
/>
However, I don't think this will get your your this.props.url and this.props.btnName. this.props.path, yes ..but you may have to revisit some logic there.
UPDATE:
After reading your comment and checking your repo, it doesn't look like there's anything wrong with your setup. I have emulated your BubblesortVideo -> VideoContainer hierarchy at the following:
https://stackblitz.com/edit/react-eaqmua

Related

<Route > component alternative in nextjs

I have 3 components in nextjs and i want to achieve the below snippet in nextjs
<Route path="/" component={homePage} />
<Route path="/about" component={aboutPage} />
<Route path="/faq" component={faqPage} />
Q1. How can i do the same in nextjs without page refresh? (without react-router)
(Edit : some scholars are suggesting to read the docs but i have read it thoroughly and what i want is to pass a component along with the route)
Is this even possible in next js?
Q2: If i have url as /products?product_id=productid and on refresh if i want the url to be /products (basically i want to remove all params on refresh) What is the best practice to do this?
Thanks in advance
NextJS functions on a convention-based filesystem-based routing. You'd need to place your components in a directory structure that matches the routes you are wanting.
More details here:
https://nextjs.org/docs/routing/introduction
The Next.js docs don't really cover how to change away from <Route> components, however they have a lot of examples as code on how to do most things with Next.js. https://github.com/vercel/next.js/tree/canary/examples/layout-component
The below is what I used as an alternative to the component (there's no direct Next.js alternative).
_app.js
export default function MyApp({ Component, pageProps }) {
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout || ((page) => page)
return getLayout(<Component {...pageProps} />)
}
Any page:
import Layout from '../components/layout'
import Sidebar from '../components/sidebar'
export default function About() {
return (
<section>
<h2>Layout Example (About)</h2>
<p>
This example adds a property <code>getLayout</code> to your page,
allowing you to return a React component for the layout. This allows you
to define the layout on a per-page basis. Since we're returning a
function, we can have complex nested layouts if desired.
</p>
<p>
When navigating between pages, we want to persist page state (input
values, scroll position, etc) for a Single-Page Application (SPA)
experience.
</p>
<p>
This layout pattern will allow for state persistence because the React
component tree is persisted between page transitions. To preserve state,
we need to prevent the React component tree from being discarded between
page transitions.
</p>
<h3>Try It Out</h3>
<p>
To visualize this, try tying in the search input in the{' '}
<code>Sidebar</code> and then changing routes. You'll notice the input
state is persisted.
</p>
</section>
)
}
About.getLayout = function getLayout(page) {
return (
<Layout>
<Sidebar />
{page}
</Layout>
)
}
The main part for the layout that you want to wrap around the pages, components/layout.js:
import Head from 'next/head'
import styles from './layout.module.css'
export default function Layout({ children }) {
return (
<>
<Head>
<title>Layouts Example</title>
</Head>
<main className={styles.main}>{children}</main>
</>
)
}
What's happening is the _app.js wraps all pages inside the declared layout. Each page then defines what layout that page belongs to. The layout then accepts a page as the {children} prop object of which you can then render anywhere in your layout page.
Next uses filesystem based routing, your folder structure should look like
-- pages
-- index.js
-- about/index.js
-- faq/index.js
For the custom component part, make a component that's clickable, on click, use next builtin router to redirect
const router = useRouter();
router.push('/');

Why is this React Router redirect not working? How to make it work?

Why is the following React Router redirect not working? How can I make it work?
<div>
<Route path = "/" exact component = {Slideshow} />
<Route path = "/favourite-movies/1" exact component = {TopMovies} />
<Redirect from = "/film/abc/:id" to ="/film/:id" />
<Route path = "/film/:id" exact component = {Film} />
</div>
Let me elucidate my intention. The favourite movies section contains some elements which link to /film/:id, (dynamically). Say id = 100. In film/100 page , I have a list of recommended movies, which in turn also links to /film/:id. When I am directly calling say film/50 from film/100 page, even though the url changes to film/50, the content remains the same. Then I refresh the page which results in the contents of film/50 being rendered.
To prevent this I am calling film/abc/50 from film/100. I want to redirect the film/abc/50 page to film/50 page. Is this a feasible solution of the problem? How can I solve this problem? Please clarify.
Each Route in React-Router must be child of Switch or Router.
Do you have your Route in Switch or Router component placed?

The <Link> from react-router-dom does not change the URL

I am currently in process of making a website, and hit a wall on this. I am using react-router-dom for routing my app, and kinda new to it, but in one page, the link that I put on the page does not change the URL
I already tried on previous component, in which I put the button on one component, then use the Link to load another component based on the Link and Route given. However, on this one, despite using similar structure as before, does not work at all
This is the code for the page that loads. I already imported the BrowserRouter as Link from react-router-dom
<div>
<p>TEST</p>
<Link to="/leadslist"><button class="btn btn-success">Back to Leads List</button></Link>
</div>
This is the target page
<div>
<Router>
<Switch>
<Redirect from="/leads" to="/leadslist" />
<Route path="/leadsForm" component={LeadsForm} />
<Route path="/leadslist" component={LeadsList} />
<Route path="/leaddetails" component={LeadsDetails}/>
</Switch>
</Router>
</div>
my previous try clicking button from "/leadslist" to "/leadsForm" actually worked, but then I try to load to "leaddetails" to try to go back to "/leadslist", but it doesn't change the URL at all. Any help will be truly appreciated.
You should not be importing BrowserRoute as Link from the react-router-dom. Both are different things. You need to import Link directly from react-router-dom. Rest, it should work solid.
You should be importing link this way:
import { Link } from "react-router-dom";
Now, I am not sure what's exactly happening your app. But here, I have created a very basic demo or working react-router using CodeSandBox. You can take a look, it should help you fix the problem you are having.
Also, you can read this article to further understand the working of the react router.
Your code doesn't work because you have added button inside Link tag so on click of button React only fires onClick method of button and Link will no be clicked!
So in solution, you can remove a button from Link tag
<Link to="/leadslist">Back to Leads List</Link>
or You can use Below solution,
Instead of adding button in Link You should do this,
import withRouter from 'react-router-dom'
const Component = (props) => {
<div>
<Button onClick={()=>props.history.push('/leadslist')}
</div>
}
export default withRouter(Component)
Add HOC withRouter to your component and you can get history object in prop.

How to add both a header.html and a footer.html to all your routes when using singlepage?

We currently have a header.html and a footer.html that we include in our base.html that is loaded in the / route of our website. We're using a single page design and thus we don't reload base.html at any time other than when initially loading the page. In base.html we have a div with an id that we use to load all our html content with jQuery to. The problem we're facing now is that fact that accessing a route directly bypasses the load of header, and thus our jQuesry-scripts and bootstrap etc., and then the page looks like crap and doesn't work properly.
We figured we could remove the visual URL-change completely and use madeup route-names in our routes instead. But that feels like an overly complicated and not neccessarily secure way of doing it.
Ideally we would like to be able to know if the request is not coming from where it's supposed to.
Any ideas of how this can be accomplished? Or do you generally just expect no one to go to /signup on their own?
I use a Nav component which renders the "chrome" around the page.
export class Nav extends Component {
render = () => {
return (
<div>
<rb.Navbar>
<rb.Navbar.Header>
<rb.Navbar.Brand>
aktai
</rb.Navbar.Brand>
</rb.Navbar.Header>
</rb.Navbar>
{this.props.children}
</div>)
}
}
I mount it to all routes in React Router:
const router = (
<Router history={browserHistory}>
<Route component={Nav}>
<Route path="/folders" component={Folders}/>
</Route>
</Router>
)
You can also call it like:
<Nav>
<h1>welcome to my site</h1>
This is a place
</Nav>
Any component which renders this.props.children will work like that.

React-Router Questions/Issues

I've decided to use React-Router to manage the routing of my Meteor JS App that uses REACT JS.
I've gotten React-Router to work 'somehow', but it is having some negative side effects that I would like to explain here, in the hopes of finding a solution.
First of all, here is my code:
if (Meteor.isClient) {
Meteor.startup(function () {
console.log('startup');
Hooks.init();
const {Router, Route} = ReactRouter;
const history = ReactRouter.history.useQueries(ReactRouter.history.createHistory)()
React.render((
<Router >
<Route name="home" path="/" component={Sidebar}>
<Route name="managedata" path="managedata" component={ManageData} />
</Route>
</Router>
), document.getElementById("render-target"));
});
}
and in order to navigate between those two routes I've used the Link component provided by React-Router:
<ReactRouter.Link className="item" to="/">
<i className="home icon"></i>
EXAMPLE
</ReactRouter.Link>
<ReactRouter.Link className="item" to="managedata">
<i className="block layout icon"></i>
Manage Data
</ReactRouter.Link>
This is the problem:
1.) Upon loading of the homepage which has the "/" as the path, I am getting random characters showing the URL. This is ugly especially since one would only expect "/" or just nothing to show in the url aside from the domain name or localhost....
e.g. http://localhost:3000/#/?_k=q2c52z
2.) When I click on the Link to 'managedata' I am also getting some random characters in the URL
e.g. http://localhost:3000/#/managedata?_k=6clzfn
Here are my questions:
1.) What is causing those ugly characters to show up in the URL and how do I get rid of them?
2.) Does Link only use the path value? As you can see above, my homepage has a name "home" but a path of "/", I've noticed that if I change the Link to Link to="home" then I get directed to a URL with a "home" on the path which seems to be incorrect.
3.) I ended up using 'component' above as one of the props in Route. I've noticed that many of the examples on the internet uses 'handler'. However, when I use 'handler' in my code.....it doesn't work.....
How are those different?
4.) I've defined my routes as above, but when I use the page does not render initially, but if I click back button on the browser and then click the forward button, then it renders. How do I solve this?
Many hours ago I had the above problems.
Now I've found the solution and I'd like to post it here in the hopes of saving some time for future readers who bump into the same problem.
Here is the Q and A:
1.) What is causing those ugly characters to show up in the URL and how do I get rid of them?
As per https://github.com/rackt/react-router/blob/master/UPGRADE_GUIDE.md
"If you do not specify a history type (as in the example above) then you will notice some unusual behaviour after updating to 1.0.0. With the default hash based routing a querystring entry not defined by yourself will start appearing in your URLs called "_k". An example of how it looks is this: ?_k=umhx1s. "
So add 'history' into the Router.
e.g.
const {Router, Route, IndexRoute} = ReactRouter;
const history = ReactRouter.history.useQueries(ReactRouter.history.createHistory)()
React.render((
<Router history={history}>
<Route path="/" component={Sidebar}>
<IndexRoute component={Dashboard} />
<Route path="managedata" component={ManageData} />
</Route>
</Router>
), document.body);
Notice the history={history} inside the Router.
2.) Does Link only use the path value? As you can see above, my homepage has a name "home" but a path of "/", I've noticed that if I change the Link to Link to="home" then I get directed to a URL with a "home" on the path which seems to be incorrect.
After reading and experimenting....
The value of 'to' should be the path.
Not only should it be the path, it should be the path surrounded by {}.
For example, for the route defined above the Link should be used like this:
<Link to={"/"} className="item" >
<i className="home icon"></i>
EXAMPLE
</Link>
<Link to={"/managedata"} className="item" >
<i className="block layout icon"></i>
Manage Data
</Link>
The surrounding {} made an important difference for me.
Otherwise the page would not render initially....I had to click back and forward again on the browser for the page to render.
3.) I ended up using 'component' above as one of the props in Route. I've noticed that many of the examples on the internet uses 'handler'. However, when I use 'handler' in my code.....it doesn't work..... How are those different?
https://github.com/rackt/react-router/blob/master/UPGRADE_GUIDE.md
Based on the above link, it is the difference between the old API and the new API.
4.) I've defined my routes as above, but when I use the page does not render initially, but if I click back button on the browser and then click the forward button, then it renders. How do I solve this?
I've answered this problem in the answer to number 2.).
But basically, for me, I added {} around the path and it started to render properly.
e.g.
<Link to={"/managedata"} className="item" >
<i className="block layout icon"></i>
Manage Data
</Link>

Categories