After working with Flask and Jinja2 server-side templating, I've decided to move my template rendering to Frontend using React. At this stage I' trying to wrap my mind around redirecting.
In the following example, I have someone clicking on a link to a given endpoint, but this requires a task being completed beforehand.
Backend
Menus.html
<li><a href="{{ url_for('cooking') }}";>Pasta</a>
When user clicks the link to 'pasta', I render some animation, and when task is done, user gets redirected to desired endpoint, like so:
Cooking.html
<div class="dish"></div>
<p class="txt">Cooking your pasta...</p>
<script> window.location.replace('/pasta');
</script>
Frontend
Now I'm trying to reproduce this using React. So far I have:
In (simplified) Menus.jsx:
import Cooking from './Cooking.jsx';
render(){
return (
<div>
<Cooking/>
</div>
);
}
}
And in Cooking.jsx:
import { Link } from 'react-router-dom';
const Cooking = (props) => (
<div>
<Link to="/cooking">Pasta</Link>
</div>
)
export default Cooking;
No, how do I similarly redirect(route) user to /pasta after /cooking is done?
You can use this.props.history.push('/pasta') or this.props.history.replace('/pasta') and since it's just simple animation you can add a setTimeout() just to add a delay before redirecting.
You can read more at
https://reacttraining.com/react-router/web/api/history
Related
I'm using Next.js for my application and I'm facing some issues on routing to the previous route of the application. I'm aware of the router function back() which is similar to window.history.back(), I would like to go back to the route when a Link is clicked, and if the previous link isn't from my application or is null, I would like to go to the home page as a default.
I used libraries like react-router-last-location for my react app, but I wanna see if there are better ways to do it in Next.js via next/router.
Here is my sample code:
<div className={styles['icon-container']}>
<Link href="/"><a>
<img src="icon.svg"></img>
</a></Link>
</div>
if i use router.back() in the href input, the page goes back automatically even before it loads, how do i solve this issue?
<Link> can't go outside of your app. (but router.back() can)
You can't use router.back() directly in the code, you need to do something like :
<img onClick={() => router.back()} src="icon.svg" />
<Link> does not have onClick property.
import { useRouter } from 'next/router'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.back()}>
Click here to go back
</button>
)
}
Source of info here
Right below the page you see a 'back to log' button. If someone clicks on that it will return to the left page. So in order to do so I thought using react router will do the job. But not sure how to fix that.Is there someone who can help me to point me to the right direction. Keep in mind that it will not open a new tab!
Link to working snippet to understand the bigger picture of my app. CodeSandBox snippet here
return (
<div>
{info.map((show: any) => {
console.log(show.show)
return (
<div key={show.show.id}>
<ReactMarkdown source={show.show.name}/>
{show.show.image && <img src={show.show.image.medium}/>}
{show.show.genres.map((showGenre: string, index: number) => {
return (
<div key={index}>
<ReactMarkdown source={showGenre}/>
</div>
)
})}
<div>
<Router>
<ul>
<li>
<Link to="/">See deta</Link>
</li>
</ul>
</Router>
</div>
</div>
)
})}
</div>
)
Check out this working example (I placed notes in each file):
https://codesandbox.io/s/modest-panini-hkzlv?file=/src/App.js
Overview:
there are several ways to do this
my suggestion is to use the history npm and create a history.js file
you will also need to use Router from react-router-dom
in your parent component, or in a Context provider, you can store your state
in the parent component, use react-router-dom Switch and Route to place routes
depending on implementation, conditionally render show route for async state update
in your search component, place all your Links using react-router-dom
on click Links should also update app's state of your specific selection
this selection gets passed to the show route/component
in the show component attach an on click that uses history.goBack and resets state
this might help you:
this.props.history.goBack();
it goes back to prev page
I'm using Gatsby to build a website that has a "specials" page with embedded Facebook. The Facebook embed does not display unless I manually reload the page or go directly to the "specials" page (rather than navigating to "specials" from the home page).
I have the Facebook script in my layout.js component file using React-Helmet:
export default ({ children }) => {
return (
<div id={layoutStyles.body}>
<Helmet>
// ...other tags
<script async defer crossorigin="anonymous" src="https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v5.0"></script>
</Helmet>
<Navigation />
<div id={layoutStyles.main}>{children}</div>
<Footer />
</div>
)
}
And in my specials.js file I have the rest of the code for embedding:
// ...
render() {
return (
<Layout>
<div id="fb-root"></div>
<p>Scroll to see more specials.</p>
<div id={styles.facebook} className="fb-page" data-href="https://www.facebook.com/LakesideMarcell/" data-tabs="timeline" data-width="500" data-height="" data-small-header="true" data-adapt-container-width="true" data-hide-cover="false" data-show-facepile="true"><blockquote cite="https://www.facebook.com/LakesideMarcell/" className="fb-xfbml-parse-ignore">Lakeside Lumber & Hardware LLC</blockquote>
</div>
<p>If you don't see specials here click the link above to see our specials on Facebook.</p>
</Layout>
)
}
}
export default Specials
I've tried moving the script tag around in the code but the result is the same problem. I also tried using componentDidMount with state, and a function that called window.location.reload(), but I cold not get the page to reload only once.
I've used the same code embedded in a version of the website not using Gatsby and I don't have this issue so it must be something to do with Gatsby. Is there a way to fix this or reload the page once without user action?
I get how to specify where to render the reactjs application by using the render method and specifying the html tag where it should be rendered.
What I do not understand is how you can have a list of react.js applications that is dynamically loaded into that same HTML tag.
For example there is a sidebar which is dynamically created to give a user a list of N number of react.js applications. When the user clicks on one of the links it loads that application into the HTML tag (div or whatever) container on the right.
I am sure this may be something easy but have been struggling with this concept for awhile.
Would appreciate any inputs anyone has on this.
If you truly had multiple full apps you wanted to swap out, you'd have to manually mount and unmount them. Something like a function like this, that unmounts the previous app, then mounts a new one. Example
function swapApp(App) {
const appNode = document.getElementById('app')
ReactDOM.unmountComponentAtNode(appNode)
ReactDOM.render(<App />, document.getElementById('app'))
}
But that would be a pain. So, typically, that menu and the content being changed are all part of the same react app. This app would render the menu, keep state about what item you clicked, and then render some components conditionally, depending on what was clicked.
Something like this example
function App() {
const [showingItem, setShowingItem] = React.useState(null)
return (
<>
<p><a href="#" onClick={() => setShowingItem('A')}>Show Item A</a></p>
<p><a href="#" onClick={() => setShowingItem('B')}>Show Item B</a></p>
{showingItem === 'A' ? <AppA /> : null}
{showingItem === 'B' ? <AppB /> : null}
</>
)
}
I'm using gatsby js and trying to figure out how to have a page level side bar with Gatsby links that render a new component inside a div in the same page I can do this using react-router-dom but in Gatsby all I can find is how to create blog posts which is driving me nuts as every tutorial I find is the same blog post.
Here is my layout page /layouts/index.js
export default ({ children }) => (
<div id="layout">
<header>
<h3>Header</h3>
<MainNav />
</header>
{children()}
</div>
)
About Page
/pages/about.js
export default ({ location, match }) => {
console.log('location = ', location, 'match = ', match );
return (
<div id="about">
<SideBar />
<div id="content">
// . add child template or component for link clicked in sidebar
</div>
</div>
);
};
What I'm trying to do is when a user clicks on a link in the side bar stay on about but render a new component or template based on the gatsby-link clicked in the about sidebar.
The About SideBar component
/components/about/side-bar.js
const SideBar = () => {
return (
<div id="side-bar">
{/* <li><Link to='/about?sort=name'>work</Link></li> */}
<li><Link to="/about/work">work</Link></li>
<li><Link to='/about/hobbies'>hobbies</Link></li>
<li><Link to='/about/buildings'>buildings</Link></li>
</div>
)
}
Problem with the links above, they are trying to go to a new page called.
/about/work
This is not what I'm trying to do. Again I'm trying to make it stay on about but render a new component inside the content div.
Please help gatsby is so all over the place as far as docs goes. ok maybe its just me and not getting the docs clearly.
Thanks
UPDATE:
I tried adding a page suing createPage which works for me kind of but it doesn't pass the match.params id
gatsby-node.js
exports.createPages = ({ boundActionCreators }) => {
const { createPage } = boundActionCreators;
const myComponent = path.resolve('src/pages/about/index.js');
createPage({
path: '/about/:id',
component: myComponent
})
}
After a long time of trying to understand Gatsby and I can say I still don't as its docs are vast and not very clear. But once I started to look at the node-apis and onCreatePage it gave me some ideas. This is what the docs literally say.
onCreatePage
Called when a new page is created. This extension API is
useful for programmatically manipulating pages created by other
plugins e.g. if you want paths without trailing slashes.
So the only part in here that gives me a hint of this might be the key to helping me is this line. useful for programmatically manipulating pages created by other
plugins
Anyway this got me writing some code at least. Then about 3 hours later I found a plugin that was doing exactly what I was trying to do with this method. The plugin is called gatsby-plugin-create-client-paths key here is client-paths!!!!!
This makes life worth living! So in my case above I just wanted to be able to use Gatsby's router ( which is just react-router-dom behind the scenes), to pass me and id or value to routers match.params object. It still doesn't but what it does do is checks for any path after a prefix like /folder/ in my case '/about/work and recreate the page with a template component (in my case keep using pages/about/index.js), which is my template. Now that we have about/index.js rendering for ever link after /about/ then we can use some internal switch statement to handle the location that is been passed to /about/index.js. Still don't get match.params update but I do get props.location.pathname; which allows me to extract everything after the prefix to use in a switch statement to render my specific components based on the routes pathname. Enough rabbiting on here is a rough solution to show as an example.
So add the plugin as an npm install.
open up gatsby.config.js and add the below code to the exports.
module.exports = {
plugins: [
{
resolve: `gatsby-plugin-create-client-paths`,
options: { prefixes: [`/about/*`] },
},
]
}
Then in my main about page pages/about/index
import React from "react";
import SideBar from '../../components/about/side-nav';
export default (props) => {
const { pathname } = props.location;
var n = pathname.lastIndexOf('/');
var pageId = pathname.substring(n + 1);
const page = () => {
switch(pageId){
case '':
return (
<div>Work Page</div>
);
case 'work':
return (
<div>Work Page</div>
);
case 'hobbies':
return (
<div>Hobbies Page</div>
);
case 'buildings':
return (
<div>buildings Page</div>
);
}
}
return (
<div id="about">
<SideBar />
<div id="content">
{page()}
</div>
</div>
);
};
Then in my sidebar I call it like this.
<li><Link to="/about/work">work</Link></li>
<li><Link to='/about/hobbies'>hobbies</Link></li>
<li><Link to='/about/buildings'>buildings</Link></li>
Hopefully this will help someone else out. After all this I'm starting to really question the bulk of gatsby especially with docs not been very clear. Based on the response to my question I guess not many people in stackoverflow's community are using Gatsby which is worrying when you need help. It does look like Gatsby's github community is very helpful but that should be for bug issues and not for questions like mine, but encouraging to see.
Hope this helps someone.