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:
parent
968475fb95
commit
8fdb133903
|
@ -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>
|
||||||
|
|
16
examples/with-typescript/components/ListDetail.tsx
Normal file
16
examples/with-typescript/components/ListDetail.tsx
Normal 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;
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
46
examples/with-typescript/pages/detail.tsx
Normal file
46
examples/with-typescript/pages/detail.tsx
Normal 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
|
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
34
examples/with-typescript/utils/sample-api.ts
Normal file
34
examples/with-typescript/utils/sample-api.ts
Normal 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
|
||||||
|
}
|
Loading…
Reference in a new issue