I'm trying to implement sliding transitions in my app between two client-only routes. It was working but now I need to make changes to gatsby code to get it working again. It seems like on location.path changes, the entire page gets rendered again causing the animating components to be lost.
These are the hacky changes I'm making to fix the animation. I've also included my code as I very well could be doing something wrong there also, but it was working and works after the below modifications.
Development
Remove the following line so that the entire component doesn't update when I navigate('login/challenge') to the next component.
https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/cache-dir/json-store.js#L75
This is the recent change that added that line that I have to remove https://github.com/porfirioribeiro/gatsby/commit/e91b392bb9b7f67b97ad7e15578447ecb5750782
Production
Add a 'return false' on this line so that location.key changes don't trigger a component update.
https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/cache-dir/ensure-resources.js#L81
import React from 'react'
import { TransitionGroup, CSSTransition } from 'react-transition-group'
import { Router, Location } from '@reach/router'
const childFactoryCreator = props => child => React.cloneElement(child, props)
const SlideTransitionRouter = ({ children }) => (
<Location>
{({ location }) => {
return (
<TransitionGroup childFactory={childFactoryCreator({classNames: 'slide', timeout: 1000})}>
<CSSTransition
key={location.key}
timeout={1000}
classNames='slide'
>
<Router location={location}>{children}</Router>
</CSSTransition>
</TransitionGroup>
)}}
</Location>
)
class Login extends React.Component {
render() {
const { classes } = this.props
return (
<SlideTransitionRouter>
<LoginForm path="/*" />
<ChallengeForm path="login/challenge" />
</SlideTransitionRouter>
)
}
}
gatsby-node.js
exports.onCreatePage = ({
page,
actions
}) => {
const {
createPage,
deletePage
} = actions
if (page.path.includes('404')) {
return Promise.resolve()
}
if (page.path.match(/^\/login/)) {
page.matchPath = `/login/*`
// Update the page.
createPage(page)
}
}
Edit - Updated with sample project and video
I've created an example project that shows what I'm trying to achieve:
https://github.com/jrestall/gatsby/tree/jrestall/client-transition-example/examples/using-client-transitions
I've also made a video of the example project. You can see how when I remove line 75 of json-store.js the animation starts working.
![]()
I should see a smooth transition of one component that slides left while the other slides in from the right. The entire DOM shouldn't be updated when a new route is navigated to.
The entire DOM gets updated and the new component appears with no animation.
System:
OS: Windows 7
CPU: x64 Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
Binaries:
npm: 6.1.0 - C:\Program Files\nodejs\npm.CMD
npmPackages:
gatsby: 2.0.18 => 2.0.18
gatsby-image: 2.0.13 => 2.0.13
gatsby-plugin-manifest: 2.0.4 => 2.0.4
gatsby-plugin-nprogress: 2.0.5 => 2.0.5
gatsby-plugin-offline: 2.0.5 => 2.0.5
gatsby-plugin-page-creator: 2.0.1 => 2.0.1
gatsby-plugin-react-helmet: 3.0.0 => 3.0.0
gatsby-plugin-resolve-src: 1.1.4 => 1.1.4
gatsby-plugin-root-import: ^2.0.4 => 2.0.4
gatsby-plugin-sharp: 2.0.6 => 2.0.6
gatsby-source-filesystem: 2.0.1 => 2.0.1
gatsby-source-graphql: 2.0.3 => 2.0.3
gatsby-transformer-sharp: 2.1.3 => 2.1.3
@jrestall did you had a chance to look at using-page-transitions example?
Hi @kakadiadarpan,
Thanks for the example, it isn't using client-only routes though, are there any examples that show GatsbyJs being used as a hybrid app with animations of the client only components that are tied to the page URL?
It would be great if we could find a way to use gatsby for a more dynamic web app with client-only routes and animations :)
This project run or not, please help me hot to run this
I've created an example project that shows what I'm trying to achieve:
https://github.com/jrestall/gatsby/tree/jrestall/client-transition-example/examples/using-client-transitions
I've also made a video of the example project. You can see how when I remove line 75 of json-store.js the animation starts working.
Hi sir please give me yours contact information via social media,I want help from you
Also I just took a look at the transitions in the existing client only paths example and they aren't fading between screens unless I make similar changes to json-store.js and I assume ensure-resources.js. https://github.com/gatsbyjs/gatsby/tree/master/examples/client-only-paths
Can anyone else confirm?
@psnaik, if you have a question why not post it publicly here or on https://spectrum.chat/gatsby-js and then others with far more gatsbyjs experience than I will be able to help.
I'm not sure what the recommended way is here, but doing something similar to what the using-page-transitions example does seems to work.
With Gatsby v2, there are no special layouts anymore - layouts are just components that live in pages. To have something stable across route changes we can use the wrapPageElement browser API. So in the client-side routing case, the strategy would have to be to move the Router in a Wrapper component that's rendered by wrapPageElement, I think.
Ok so I modified your example project and wrapping everything in wrapPageElement works - the index page is just a noop function so there is something to wrap. As I said, not sure if this how it should be done. In any case, the client-only-paths example needs to be fixed as well. Have a look with
git clone https://github.com/stefanprobst/gatsby.git
cd gatsby
git checkout issue8822
cd examples/using-client-transitions
yarn install
yarn develop
Thanks @stefanprobst, looks like using the gatsby-plugin-layout or wrapPageElement is the only way to go currently.
That's unfortunate since it makes coding a complex app with a lot of nested routers very complex and forces very different approaches compared with ReactJS when using client only routes.
I'd be curious to know why ensure-resources.js forces a complete page re-render on location change in this scenario? If the login page's location is /login and the new URL is /login/challenge that only matches a nested router on that same page, why does the entire page have to re-render if it's already on the 'login page'?
All of the resources for that login page should have already been downloaded when the /login route was hit?
@KyleAMathews @pieh I'd really appreciate your insight on this.
I ended up patching ensure-resources.js to fix this for my use case. It's working currently but I'm sure it'll break in ways I'm yet to discover.
shouldComponentUpdate(nextProps, nextState) {
...
// Don't refresh the page if we are using client-only routing and the new location is a nested route of the same page.
if (
this.state.pageResources.page &&
this.state.pageResources.page.matchPath &&
this.state.pageResources.page.path === nextState.pageResources.page.path &&
nextProps.location &&
(nextProps.location.pathname.startsWith(this.state.location.pathname) ||
this.state.location.pathname.startsWith(nextProps.location.pathname))
) {
return false
}
...
}
I had another look at this and to me the issue seems to be that pages are rendered with pathname as their key:
Commenting this out fixes your example and the client-only-paths example as well.
Edit: The key in page-renderer is actually a quite recent addition, and in the end a consequence of trying to fix #8181. I think this fix was the wrong approach, because the real issue there is plugins working around/against React's reconciler.
@stefanprobst very nice find! It would make sense that something recent broke my transitions since I'm sure this was working fine a month or so ago.
I'll look into changing my patch to just remove that line as that is a lot simpler fix.
Edit: Also maybe that will fix both the development and production builds which would be great.
Thanks a lot for your help on this @stefanprobst, based on your finding I managed to remove my patches to gatsby and just replace the default renderer to fix the issue in my gatsby-browser.js.
var createElement = require('react').createElement
exports.replaceComponentRenderer = ({ props }) => {
return createElement(props.pageResources.component, {...props})
}
Old issues will be closed after 30 days of inactivity. This issue has been quiet for 20 days and is being marked as stale. Reply here or add the label "not stale" to keep this issue open!
Hey again!
It鈥檚 been 30 days since anything happened on this issue, so our friendly neighborhood robot (that鈥檚 me!) is going to close it.
Please keep in mind that I鈥檓 only a robot, so if I鈥檝e closed this issue in error, I鈥檓 HUMAN_EMOTION_SORRY. Please feel free to reopen this issue or create a new one if you need anything else.
Thanks again for being part of the Gatsby community!
Most helpful comment
Thanks a lot for your help on this @stefanprobst, based on your finding I managed to remove my patches to gatsby and just replace the default renderer to fix the issue in my gatsby-browser.js.