Suspense Like Data Fetching 🚀
Changed getInitialProps
Behavior
Old Behavior
URL Change -> getInitialProps get called -> matched component get renderd on screen -> getInitialProps resolved -> component gets re-renered and can acess getInitialProps data from it's props
this is very bad and there are some problems:
- very bad UX, this will cause page jank since matched component gets rendered on-screen without any data, and we have to show
<Spinner />
tillgetInitialProps
resolved - scroll to top happen after
getInitialProps
resolved, so the user will see nothing (or footer) for a while - if we use data from
getInitialProps
with hooks, we have to write very complicated code
function PageB({ data })
const [count, setCount] = React.useState(data)
if (!data) return <Spinner />
return <span>{count}</span>
}
PageB.getInitialProps = () => {
return new Promise(reslove => setTimeout(() => reslove({ data: 1 }) , 3000))
}
data
is undefined so count is undefined, and to fix it we have to write an effect like below:
React.useEffect(() => {
setCount(data)
}, [ data ])
New Behavior:
URL Change -> getInitialProps get called -> wait's on current location until getInitialProps resolved -> render matched component with data from getInitialProps
When a user moves from page /a
to page /b
, URL changes but the user still sees /a
page on the screen till /b
page data get fetched.
Custom Document.js
Now we have a simpler custom Document with <AfterScripts />
and <AfterStyles />
.
Any params that passed to getInitialProps
and return values of it are available from __AfterContext
.
import { __AfterContext } from "@jaredpalmer/after"
Use this context to build components for your custom Document.
import React from 'react';
import { AfterScripts, AfterStyles, AfterRoot, AfterData } from "@jaredpalmer/after"
class Document extends React.Component {
static async getInitialProps({ renderPage }) {
const page = await renderPage();
return { ...page };
}
render() {
const { helmet } = this.props;
// get attributes from React Helmet
const htmlAttrs = helmet.htmlAttributes.toComponent();
const bodyAttrs = helmet.bodyAttributes.toComponent();
return (
<html {...htmlAttrs}>
<head>
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta charSet="utf-8" />
<title>Welcome to the Afterparty</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
{helmet.title.toComponent()}
{helmet.meta.toComponent()}
{helmet.link.toComponent()}
<AfterStyles />
</head>
<body {...bodyAttrs}>
<AfterRoot />
<AfterData />
<AfterScripts />
</body>
</html>
);
}
}
- use yarn 9a26b30
- ts-jest ignore diagnostics 3ae6831
<AfterScripts />
,<AfterStyles />
(#279) 287c7c8- update package dependecies (#278) 7a9eb5b
- Fix always positive result (#230) 54a14a2
- Update docs (#270) b4329f7
- fix typo (#213) c446608
- Create main.yml 22407ab
- Merge pull request #234 from nimaa77/code-cleanup 4647374
- Merge branch 'master' into code-cleanup 2063ac2
- Merge pull request #264 from nimaa77/fix-data-fetching-fix-1 c9b8a03
- Merge pull request #235 from nimaa77/feature/error-pages-fixes bba8d5a
- Merge branch 'master' into code-cleanup 7088e27
- fix AfterParty 95144f8
- Fix data fetching (🚀 SUSPENSE but not suspense 🚀) (#251) 3112cd4
- a better title for 404 Page 4866edc
- fix test case for notfoundcomponent db85fb4
- remove "*" from readme.md 2ab908d
- format code with prettier c3143db
- remove with space after OS: e856d36
- add prettier ignore file ecbdfb2
- allow doctoc with prettier 4653ba4
- allow prettier to format all supported file extentions 695e22c