Hey @mikeriley131 
First, super neat site. Design is awesome 
Did quite a bit of experimentation and code-checking on what’s going on here. Definitely a fringe case with React hydrating / Gatsby’s build-ahead workflow. To summarize what you’re experiencing, it’s a non-determinant behavior that can be viewed by checking the class
of the <div>
that’s a direct child of the article.contact-page
. When the location hash is not #success
, the aforementioned ‘target div’ should have the class contact-page__content-wrapper
but when the hash is present, the target div should instead maintain the class contact-page__success
.
All the while, from what I can tell, the markup using either class appears to finally render the same. Is that true?
Here’s what I found. When you browse to the path /contact-neue
for the first time (or on a hard refresh), the contact-page__content-wrapper
is used and the form is displayed within. This is (I believe) desired / normal behavior. From that point, if you manually add the #success
path to the URL (without filling out the form), the success message appears and the contact-page__success
class is applied. This is akin to the Reach router making an intra-site navigation so it makes sense that the router would be fully hydrated and updated with the location
.
That said, if you cold-load (or hard refresh) directly on the /contact-neue#success
path, the success message is displayed but the contact-page__content-wrapper
class is used. For the sake of the form, when you POST a form to Netlify, the response simply contains the static page content for the targeted action
attribute on that form… so the workflow is akin to cold-loading the /contact-neue#success
path. It’s not an intra-site navigation as far as the React runtime is concerned; you’re fully loading a new page and then re-initializing the React runtime at that point. (Which is why you actually get a flash of the form before it switches to the success page – the statically generated HTML was the form, not the success).
So the real question is, why, on cold-load / hard refresh of the /contact-neue#success
path, does React go ahead with rendering the <ContactSuccess />
component, but for whatever reason not actually replace the class on the already-existing div from contact-page__content-wrapper
to contact-page__success
. I’m wondering if it’s a mis-hydration concern since the underlying HTML structure contained from that div down doesn’t actually change; just that one class tag.
In your page component declaration you’re doing: const ContactNeue = ({ data, location }) =>
then directly using the location
object lower down in your ternary. I wonder if somehow there’s just a disconnect in the value of that particular prop between build time and runtime when you load the #success
path directly. Could you try instead going from
import React from 'react';
import PropTypes from 'prop-types';
import { graphql } from 'gatsby';
import { Layout } from '../components/layout';
import SEO from '../components/seo';
import { ContactForm } from '../components/contactForm';
import { ContactSuccess } from '../components/contactSuccess';
const ContactNeue = ({ data, location }) => {
const contactData = data.neueamsterdam.page.contactPage;
return (
<Layout>
<SEO title="Contact Neue" />
<div className="container">
<article className="contact-page">
{location.hash === '#success' ? (
<ContactSuccess />
) : (
<ContactForm
title={contactData.title}
introCopy={contactData.introCopy}
/>
)}
</article>
</div>
</Layout>
);
};
to something more like:
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { graphql } from 'gatsby';
import { Layout } from '../components/layout';
import SEO from '../components/seo';
import { ContactForm } from '../components/contactForm';
import { ContactSuccess } from '../components/contactSuccess';
const ContactNeue = ({ data, location }) => {
const contactData = data.neueamsterdam.page.contactPage;
const [showSuccess, setShowSuccess] = useState(false)
useEffect(() => {
if (location.hash === '#success') {
setShowSuccess(true)
}
}, location.hash)
return (
<Layout>
<SEO title="Contact Neue" />
<div className="container">
<article className="contact-page">
{showSuccess ? (
<ContactSuccess />
) : (
<ContactForm
title={contactData.title}
introCopy={contactData.introCopy}
/>
)}
</article>
</div>
</Layout>
);
};
? I’m recommending this because useEffect()
guarantees that the effect chunk of code will run only at runtime (on a browser, not during build), then the state change would guarantee an effective re-render, and the useEffect
dependency should track with the location.hash
.
If you’re up for giving that a try, let me know if it works!
–
Jon