1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00

[with-typescript] Improved intial props examples, added example detail (#6165)

I've just thought of a way to improve the initial props page by adding
an example for a list/detail page structure. To do that, I've created a
separate `/detail` page, and a mock API which calls data from the array
we made on the previous PR.

A ListDetail component is created as an example for displaying detail.

Page structure is also cleaned up. Should I go ahead and add an example
on how to style with styled-jsx + its TS declarations? I might decide to
do it within this week anyway.
This commit is contained in:
Resi Respati 2019-02-01 00:36:02 +07:00 committed by Tim Neutkens
parent 968475fb95
commit 8fdb133903
9 changed files with 126 additions and 21 deletions

View file

@ -16,8 +16,8 @@ const Layout: React.FunctionComponent<Props> = ({ children, title = 'This is the
<header> <header>
<nav> <nav>
<Link href='/'><a>Home</a></Link> | {' '} <Link href='/'><a>Home</a></Link> | {' '}
<Link href='/list-fc'><a>List as Functional Component</a></Link> | {' '} <Link href='/list-class'><a>List Example</a></Link> | {' '}
<Link href='/list-class'><a>List As Class</a></Link> | {' '} <Link href='/list-fc'><a>List Example (as Functional Component)</a></Link> | {' '}
<Link href='/about'><a>About</a></Link> | {' '} <Link href='/about'><a>About</a></Link> | {' '}
</nav> </nav>
</header> </header>

View file

@ -0,0 +1,16 @@
import * as React from 'react'
import IDataObject from '../interfaces';
type ListDetailProps = {
item: IDataObject;
}
const ListDetail: React.FC<ListDetailProps> = ({ item: user }) => (
<div>
<h1>Detail for {user.name}</h1>
<p>ID: {user.id}</p>
</div>
)
export default ListDetail;

View file

@ -1,4 +1,6 @@
import * as React from 'react' import * as React from 'react'
import Link from 'next/link';
import IDataObject from '../interfaces' import IDataObject from '../interfaces'
type Props = { type Props = {
@ -6,7 +8,9 @@ type Props = {
} }
const ListItem: React.FunctionComponent<Props> = ({ data }) => ( const ListItem: React.FunctionComponent<Props> = ({ data }) => (
<React.Fragment>{data.id}:{data.name}</React.Fragment> <Link href={`/detail?id=${data.id}`} passHref>
<a>{data.id}: {data.name}</a>
</Link>
); );
export default ListItem export default ListItem

View file

@ -4,6 +4,7 @@ import Layout from '../components/Layout'
const AboutPage: React.FunctionComponent = () => ( const AboutPage: React.FunctionComponent = () => (
<Layout title="About | Next.js + TypeScript Example"> <Layout title="About | Next.js + TypeScript Example">
<h1>About</h1>
<p>This is the about page</p> <p>This is the about page</p>
<p><Link href='/'><a>Go home</a></Link></p> <p><Link href='/'><a>Go home</a></Link></p>
</Layout> </Layout>

View file

@ -0,0 +1,46 @@
import * as React from 'react'
import { NextContext } from 'next'
import Layout from '../components/Layout'
import IDataObject from '../interfaces'
import { findData } from '../utils/sample-api'
import ListDetail from '../components/ListDetail';
type RequestQuery = {
id: number,
}
type Props = {
item?: IDataObject,
errors?: string,
}
class ListDetailPage extends React.Component<Props> {
static getInitialProps = async ({ query }: NextContext<RequestQuery>) => {
try {
const item = await findData(query.id);
return { item }
} catch (err) {
return { errors: err.message }
}
}
render() {
const { item, errors } = this.props;
if (errors) {
return (
<Layout title={`Error | Next.js + TypeScript Example`}>
<p><span style={{ color: 'red' }}>Error:</span> {errors}</p>
</Layout>
)
}
return (
<Layout title={`${item ? item.name : 'Detail'} | Next.js + TypeScript Example`}>
{item && <ListDetail item={item} />}
</Layout>
)
}
}
export default ListDetailPage

View file

@ -1,12 +1,15 @@
import React from 'react' import * as React from 'react'
import { NextContext } from 'next' import { NextContext } from 'next'
import Link from 'next/link';
import Layout from '../components/Layout' import Layout from '../components/Layout'
import List from '../components/List' import List from '../components/List'
import IDataObject from '../interfaces' import IDataObject from '../interfaces'
import { findAll } from '../utils/sample-api';
type Props = { type Props = {
items: IDataObject[], items: IDataObject[],
pathname: string,
} }
class ListClass extends React.Component<Props> { class ListClass extends React.Component<Props> {
@ -14,20 +17,19 @@ class ListClass extends React.Component<Props> {
// Example for including initial props in a Next.js page. // Example for including initial props in a Next.js page.
// Don't forget to include the respective types for any // Don't forget to include the respective types for any
// props passed into the component // props passed into the component
const dataArray: IDataObject[] = [ const items: IDataObject[] = await findAll()
{ id: 101, name: 'larry' },
{ id: 102, name: 'sam' },
{ id: 103, name: 'jill' },
{ id: 104, name: pathname },
]
return { items: dataArray } return { items, pathname }
} }
render() { render() {
const { items, pathname } = this.props
return ( return (
<Layout title="List Example | Next.js + TypeScript Example"> <Layout title="List Example | Next.js + TypeScript Example">
<List items={this.props.items} /> <h1>List Example</h1>
<p>You are currently on: {pathname}</p>
<List items={items} />
<p><Link href='/'><a>Go home</a></Link></p>
</Layout> </Layout>
) )
} }

View file

@ -1,15 +1,22 @@
import { NextFunctionComponent, NextContext } from 'next' import { NextFunctionComponent, NextContext } from 'next'
import Link from 'next/link';
import Layout from '../components/Layout' import Layout from '../components/Layout'
import List from '../components/List' import List from '../components/List'
import IDataObject from '../interfaces' import IDataObject from '../interfaces'
import { findAll } from '../utils/sample-api';
type Props = { type Props = {
items: IDataObject[], items: IDataObject[],
pathname: string,
} }
const ListFunction: NextFunctionComponent<Props> = ({ items }) => ( const ListFunction: NextFunctionComponent<Props> = ({ items, pathname }) => (
<Layout title="List Example (with Function Components) | Next.js + TypeScript Example"> <Layout title="List Example (as Functional Component) | Next.js + TypeScript Example">
<h1>List Example (as Function Component)</h1>
<p>You are currently on: {pathname}</p>
<List items={items} /> <List items={items} />
<p><Link href='/'><a>Go home</a></Link></p>
</Layout> </Layout>
) )
@ -17,14 +24,9 @@ ListFunction.getInitialProps = async ({ pathname }: NextContext) => {
// Example for including initial props in a Next.js function compnent page. // Example for including initial props in a Next.js function compnent page.
// Don't forget to include the respective types for any props passed into // Don't forget to include the respective types for any props passed into
// the component. // the component.
const dataArray: IDataObject[] = [ const items: IDataObject[] = await findAll()
{ id: 101, name: 'larry' },
{ id: 102, name: 'sam' },
{ id: 103, name: 'jill' },
{ id: 104, name: pathname },
]
return { items: dataArray } return { items, pathname }
} }
export default ListFunction export default ListFunction

View file

@ -0,0 +1,34 @@
import IDataObject from "../interfaces";
/** Dummy user data. */
export const dataArray: IDataObject[] = [
{ id: 101, name: 'Alice' },
{ id: 102, name: 'Bob' },
{ id: 103, name: 'Caroline' },
{ id: 104, name: 'Dave' },
];
/**
* Calls a mock API which finds a user by ID from the list above.
*
* Throws an error if not found.
*/
export async function findData(id: number | string) {
const selected = dataArray.find((data) => data.id === Number(id))
if (!selected) {
throw new Error('Cannot find user')
}
return selected
}
/** Calls a mock API which returns the above array to simulate "get all". */
export async function findAll() {
// Throw an error, just for example.
if (!Array.isArray(dataArray)) {
throw new Error('Cannot find users')
}
return dataArray
}