Last active
March 28, 2017 18:47
-
-
Save zackargyle/0d3fc574b45cf756ebac44c7ba36b75d to your computer and use it in GitHub Desktop.
React component for deferring rendering until post-mount.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
<DeferredMount ssr /> | |
This component defers rendering of its children until after mounting, good | |
for below-the-fold content. If the content should be rendered syncronously | |
on the server you can set the `ssr` prop. If `ssr` is set to true, there | |
will be a client/server mismatch unless you can somehow determine that we | |
are hydrating from the server. | |
Is there a better way than the hack below? | |
*/ | |
// flow | |
import { Component } from 'react'; | |
type Props = { | |
children: any, | |
ssr?: true, | |
timeout?: number, | |
}; | |
type State = { | |
mounted: boolean, | |
}; | |
const IS_SERVER = typeof window === 'undefined'; | |
/* This is hacky. If it has been server rendered, we | |
* need a way to know. This `isHydrating` flag tells us | |
* that we're probably in the server checksum stage. | |
* So render sync if props.ssr was set. | |
*/ | |
let isHydrating = true; | |
if (!IS_SERVER) { | |
if (document.readyState === 'complete') { | |
isHydrating = false; | |
} else { | |
window.addEventListener('load', () => { | |
isHydrating = false; | |
}); | |
} | |
} | |
const shouldRender = (props, state) => ( | |
(state.mounted) || | |
(props.ssr && (IS_SERVER || isHydrating)) | |
); | |
export default class DeferredMount extends Component { | |
state: State = { | |
mounted: false, | |
}; | |
componentDidMount() { | |
this.mounted = true; | |
setTimeout(() => { | |
if (this.mounted) { | |
this.setState({ mounted: true }); | |
} | |
}, this.props.timeout || 0); | |
} | |
componentWillUnmount() { | |
this.mounted = false; | |
} | |
props: Props; | |
render() { | |
const { props, state } = this; | |
return shouldRender(props, state) ? props.children : null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You use it like this
Problem is I don't see a good way to defer mounting if it's rendered client side, but render synchronously if it's rendered server side, without having a client/server mismatch. The above code works, but the window.readyState/onload hack is pretty gross. Ideas?