I have made a React web app and am hosting it through github pages, at this link here and I have a header which directs you to different pages.
When the site is opened it should default to the home page and the header titled "Home" should be highlighted orange. When you select a link, then that link becomes orange (pretty straightforward). When running locally it runs fine and reacts how I would expect.
But on GitHub Pages, it does not default to any link being "selected" when you go directly to the site, or refresh, but behaves fine when you are selecting different links after the intial load.
The gif below visually demonstrates the issue. Localhost is on the right, the real page is on the left:
https://imgur.com/a/YMZ0Hm3
I am obviously trying to fix it, but would also like to know exactly what is causing the issue because this seems like quite the little issue.
The source code can be found here.
The main routing code that is responsible is this section here from headerComponent
<Link onClick = {() => this.handleClick(Routes.HOME_PAGE) } className={this.state.url.toLowerCase() === Routes.HOME_PAGE.toLowerCase() ? 'selected':'nope'} to={Routes.HOME_PAGE}>Home</Link>
<Link onClick = {() => this.handleClick(Routes.RESUME_PAGE) } className={this.state.url.toLowerCase() === Routes.RESUME_PAGE.toLowerCase() ? 'selected':'nope'} to={Routes.RESUME_PAGE}>Resume</Link>
<Link onClick = {() => this.handleClick(Routes.COVER_LETTER_PAGE) } className={this.state.url.toLowerCase() === Routes.COVER_LETTER_PAGE.toLowerCase() ? 'selected':'nope'} to={Routes.COVER_LETTER_PAGE}>Cover Letter</Link>
Where handleClick(route) just sets this.state.url to the route passed in
I think I found the issue. In your state, you have:
this.state = {url: this.fullUrl.substr(this.fullUrl.lastIndexOf("/"), this.fullUrl.length - 1)};
This is cutting off everything except the last part of the url by default. So if the URL was https://dakotamaker.github.io/resume-site/resume, it would be setting state to /resume.
Then in your <Link>, you're checking if the url in state matches any of the routes. Assuming the process.env.PUBLIC_URL is https://dakotamaker.github.io/resume-site/, by on site load you're checking if /, /resume, /coverLetter, matches the full url equivalent. I.e.:
// before evaluation
className={this.state.url.toLowerCase() === Routes.HOME_PAGE.toLowerCase() ? 'selected':'nope'}
// after evaluation
className={'/resume' === 'https://dakotamaker.github.io/resume-site/resume' ? 'selected':'nope'}
But it works when you actually click on a link because your .handleClick function is setting the url in state to be the constant that you've defined in your Routes file. So if you click on the Resume page link, the url in state gets set to Routes.RESUME_PAGE. So when the Links check again whether it should add the class name, it's guaranteed that one link will always be selected.
So what you'll probably want to do is along the lines of not modifying the URL of the page the user first loads:
this.state = {url: this.fullUrl};
The reason is your local website is on root of localhost:3000 but your github page is on the subdirectory. To fix that, you should put 'basename' props into your Router component. It should be some thing like this
<Router history={browserHistory} basename={'resume-site'}>
<Route path="/" component={App} />
</Router>
I figured out that you have set your base name to env var. So just need to inject it while building by editing package.json:
"deploy": "PUBLIC_URL=resume-site gh-pages -d build"
Related
I am kinda new to react and I would like to change the url once the user has clicked to open a modal window. There's also some data coming with the modal that I would like to reflect in the url. E.g. "my.app/folders/project-name/"
I tried some solutions with react router but I do not seem to get it just right...
Here is the modal that I wish could update the URL once it's opened.
{modalOpen ? (
<ProjectModal
projectName={target[0].project_name}
organization={target[0].organization}
avatar={target[0].organization_avatar}
client="xy"
selectedImg={target[0].images[0]}
gallery={target[0].images}
onClose={() => setModalOpen(false)}
/>
) : null}
Make sure you have this route mentioned in your Router. Something like this,
<Route path="parent" component="ParentComponent" />
<Route path="parent/modal" component="ParentComponent" />
Then you will have to use the history.push method while setting the variable to open the modal.
history.push('/parent/modal');
Hope my answer helps.
Checkout the docs for more info.
I have an ebay ad widget that does not show when initially navigating to the page it is on. I navigate to the page using links created with Gatsby's Link component. (import {Link} from 'gatsby')
The jsx looks like.
<ins class="h-100 w-100 epn-placement" data-config-id="999999999999"></ins>
I have to ad this script to my head to get the widget to show.
<script async src="https://epnt.ebay.com/static/epn-smart-tools.js"></script>
(Removing async has no effect)
The component does load when I refresh the page or visit the page directly without navigating to it.
This problem does not happen if I use regular a instead of Link
Since <Link> (inherited from #reach/router) does not load the full page like a typical anchor (<a>) does, you may want to use a <Link>'s state to keep all features and adding the loading for your eBay widget.
In your <Link> page would be:
<Link to={`/your-ebay-page` state={{ loadWidget: true }}> To Ebay Widget Page </Link>
In your eBay page:
const EbayPage = ({ location }) => {
if (location.state.loadWidget) {
return <ins class="h-100 w-100 epn-placement" data-config-id="999999999999"></ins>
} else {
// whatever
}
}
Due to the lack of code and project structure, this is just an approach or a workaround about how to solve your issue, you should adapt it to your specifications.
I am working on a Gatsby project (a language learning blog) and am having trouble with an issue that only happens in production builds due to server-side rendering.
I programmatically generate a page for each blog post with the following scheme:
/posts/{post-name}. Each post can also have a number of subpaths that map to open tabs in the UI. For example, /posts/important-spanish-verbs/lesson would open the lesson tab. Each page has a matchPath property of /posts/{post-name}/*, and these are handled as client-only routes, implemented with reach-router.
With gatsby develop, the app works exactly as intended. When I visit /posts/some-post/podcast, it successfully opens to the podcast tab and I can see the active tab being set correctly.
The problem is that with gatsby build && gatsby serve, when I fresh-load a URL that directly navigates to a specific tab inside of the post (either manually visiting the whole URL or refreshing), the active tab is not set correctly in the UI.
The following snippet (highly simplified and condensed to demonstrate the issue) roughly outlines the problem:
function TabbedLayout({ children, basePath }) {
return (
<LocationProvider>
{({ location }) => {
return (
<Fragment>
<ul>
React.Children.map(children, (child, index) => {
const isActive = child.props.path === location.pathname
console.log(`tab ${child.props.path} active? ${isActive}`)
return <li className={isActive ? 'active' : 'inactive'}>{/* construct a link based on child props */}</li>
})
</ul>
<Router basepath={basePath}>
{children}
</Router>
</Fragment>
)
}}
</LocationProvider>
}
What happens when I run my code which uses the method demonstrated above in a production build (with SSR) is that when I visit for example posts/example-post/lesson:
The content is rendered correctly via Reach router (i.e. the content of the lesson tab is open)
The lesson tab has class inactive (an error)
In the console, I see tab /posts/example-post/lesson active? true printed, even though the CSS class didn't get updated!
I've tried everything I can think of to try to update the UI. As soon as I click a different tab and the window location changes without a refresh, everything updates fine and the active tab UI works as expected, but I just cannot seem to get it to re-render based on the isActive variable.
Does anyone know a way to fix or work around this issue?
Thanks!
I have managed to find a workaround for the issue, although it's a bit frustrating to not understand in detail why the problem is actually happening.
If I wrap the tab <li>s (which don't correctly show as active/inactive on first load with SSR) in a condition to check that we're in the browser, it works:
return typeof window !== 'undefined' && (
<li className={isActive ? 'active' : 'inactive'}>
{/* construct a link based on child props */}
</li>
)
Is there a way I can prevent the url from changing when the back button is clicked?
I'm currently using createMemoryHistory to prevent url modification when I navigate around clicking links set up in my app. By doing this, I'm able to successfully navigate around but when I click the back button in my browser, it modifies the url (which I don't want).
E.g. My url looks like localhost:3000. Then I click on the settings link and I navigate to the settings view but my link is still localhost:3000. Now in settings, I click on Printers and navigate to the Printers view inside settings. My url still looks like localhost:3000. However, if I click the back button and return to the settings page, now my url looks like localhost:3000/settings.
Is there anything . I can do to the prevent the back button from modifying my url? Thank you for your help!
I would suggest using react-router's browserHistory class like this:
import { browserHistory } from 'react-router';
//... inside your component class
componentDidMount() {
browserHistory.listen(location => {
if (location.action === "POP") {
// Do your stuff
// maybe use your `createMemoryHistory` API
// to push a / to the history to keep the URL the same?
}
});
}
Currently I have setup a small test application and ran into some trouble lately. After some tries I still don't know where my mistake is.
Here is my pen: http://codepen.io/ins0/pen/wtELa
The problem is that after clicking the side navigation the content normally shows up, navigation updates. When I click on a link inside the content - the url state changes (eg. from #/settings to #/settings/about, xhr gets fired and received but the content doesn't get replaced.
I tried listening to all state events but no error is thrown.
I found the mistake by myself. In order to get the navigation correct you need to set a a viewtarget in your router configuration for childen pages that point to your parent view. Like this:
state('app.settings.about', {
url: "/about",
views: {
'content#app' :{
templateUrl: "about.html"
}
}
});
see'content#app'. this tells the framework to render the about view in the content field defined in route app. I updated the codepen to a working example.