38
loading...
This website collects cookies to deliver better user experience
// .ts
export type GetServerSidePropsResult<P> =
| { props: P }
| { redirect: Redirect }
| { notFound: true }
export type GetServerSideProps<
P extends { [key: string]: any } = { [key: string]: any },
Q extends ParsedUrlQuery = ParsedUrlQuery
> = (
context: GetServerSidePropsContext<Q>
) => Promise<GetServerSidePropsResult<P>>
// Page.ts
import { GetServerSideProps, NextPage } from "next"
type User = {
name: string
age: number
}
type Props = { user: User }
export const getServerSideProps: GetServerSideProps<Props> = async (
context,
) => {
const response = await fetch(`https://.../user`)
const user: User = await response.json()
if (!user) {
return {
redirect: {
destination: "/",
permanent: false,
},
}
}
return {
props: { user },
}
}
const Page: NextPage<Props> = ({ user: { name, age } }) => {
return (
<div>
<p>User name: {name}</p>
<p>Age: {age}</p>
</div>
)
}
export default Page
module GetServerSideProps = {
module Req = {
type t
}
module Res = {
type t
}
type context<'props, 'params, 'previewData> = {
params: 'params,
preview: option<bool>,
previewData: Js.Nullable.t<'previewData>,
query: Js.Dict.t<string>,
req: Req.t,
res: Res.t,
}
// The type of the `getServerSideProps` function
type t<'props, 'params, 'previewData> = context<'props, 'params, 'previewData> => Js.Promise.t<{
"props": 'props,
}>
}
req
and res
properties on the context record. We declare them as opaque types because we’re not sure about their runtime representation and we actually don’t care about it. Currently our function returns a single object type with props. module Return: {
type rec t<'props>
let inject: (~props: 'props) => t<'props>
let redirect: (~destination: string, ~permanent: bool, unit) => t<'props>
} = {
@unboxed type rec t<'props> = Any('value): t<'props>
let inject = (~props) => Any({ "props": props })
let redirect = (~destination, ~permanent, ()) => Any({
"redirect": {
"destination": destination,
"permanent": permanent
},
})
}
t<'props>
to hide the underlying type of the Return module as an implementation detail. This type references itself so we need to define it as a recursive type rec
otherwise we would get a compiler error. t
is defined as a variant Any
with some payload. We are also making use of the @unboxed
attribute which strips out the variant constructor and makes its runtime representation equal to the underlying value. These two combined enable returning at runtime the two objects expected from geServerSideProps.Return.t<'props>
.type t<'props, 'params, 'previewData> = context<'props, 'params, 'previewData> => Js.Promise.t<
Return.t<'props>,
>
// Page.res
module GetServerSideProps = {
module Req = {
type t
}
module Res = {
type t
}
type context<'props, 'params, 'previewData> = {
params: 'params,
preview: option<bool>,
previewData: Js.Nullable.t<'previewData>,
query: Js.Dict.t<string>,
req: Req.t,
res: Res.t,
}
module Return: {
type rec t<'props>
let inject: (~props: 'props) => t<'props>
let redirect: (~destination: string, ~permanent: bool, unit) => t<'props>
} = {
@unboxed type rec t<'props> = Any('value): t<'props>
let inject = (~props) => Any({"props": props})
let redirect = (~destination, ~permanent, ()) => Any({
"redirect": {"destination": destination, "permanent": permanent},
})
}
type t<'props, 'params, 'previewData> = context<'props, 'params, 'previewData> => Js.Promise.t<
Return.t<'props>,
>
}
type user = {
name: string,
age: int,
}
type props = {user: user}
let getServerSideProps: GetServerSideProps.t<_, _, _> = _context => {
let {inject, redirect} = module(GetServerSideProps.Return)
let getData = () => {
// fetch the data from somewhere
Js.Promise.resolve({name: "John", age: 30})
}
getData()->Js.Promise.then_(user => {
inject(~props={user: user})->Js.Promise.resolve
}, _)->Js.Promise.catch(_error => {
redirect(~destination="/", ~permanent=true, ())->Js.Promise.resolve
}, _)
}
@react.component
let default = (~user: user) => {
let {name, age} = user
<div>
<p> {`User name: ${name}`->React.string} </p>
<p> {`Age: ${age->Js.Int.toString}`->React.string} </p>
</div>
}