From 8fdb1339037da331a23c66e748d083e46f3ee3f3 Mon Sep 17 00:00:00 2001 From: Resi Respati Date: Fri, 1 Feb 2019 00:36:02 +0700 Subject: [PATCH] [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. --- .../with-typescript/components/Layout.tsx | 4 +- .../with-typescript/components/ListDetail.tsx | 16 +++++++ .../with-typescript/components/ListItem.tsx | 6 ++- .../interfaces/{index.tsx => index.ts} | 0 examples/with-typescript/pages/about.tsx | 1 + examples/with-typescript/pages/detail.tsx | 46 +++++++++++++++++++ examples/with-typescript/pages/list-class.tsx | 20 ++++---- examples/with-typescript/pages/list-fc.tsx | 20 ++++---- examples/with-typescript/utils/sample-api.ts | 34 ++++++++++++++ 9 files changed, 126 insertions(+), 21 deletions(-) create mode 100644 examples/with-typescript/components/ListDetail.tsx rename examples/with-typescript/interfaces/{index.tsx => index.ts} (100%) create mode 100644 examples/with-typescript/pages/detail.tsx create mode 100644 examples/with-typescript/utils/sample-api.ts diff --git a/examples/with-typescript/components/Layout.tsx b/examples/with-typescript/components/Layout.tsx index a69522ac..572f1045 100644 --- a/examples/with-typescript/components/Layout.tsx +++ b/examples/with-typescript/components/Layout.tsx @@ -16,8 +16,8 @@ const Layout: React.FunctionComponent = ({ children, title = 'This is the
diff --git a/examples/with-typescript/components/ListDetail.tsx b/examples/with-typescript/components/ListDetail.tsx new file mode 100644 index 00000000..668e1722 --- /dev/null +++ b/examples/with-typescript/components/ListDetail.tsx @@ -0,0 +1,16 @@ +import * as React from 'react' + +import IDataObject from '../interfaces'; + +type ListDetailProps = { + item: IDataObject; +} + +const ListDetail: React.FC = ({ item: user }) => ( +
+

Detail for {user.name}

+

ID: {user.id}

+
+) + +export default ListDetail; diff --git a/examples/with-typescript/components/ListItem.tsx b/examples/with-typescript/components/ListItem.tsx index 90d19f46..14478cd2 100644 --- a/examples/with-typescript/components/ListItem.tsx +++ b/examples/with-typescript/components/ListItem.tsx @@ -1,4 +1,6 @@ import * as React from 'react' +import Link from 'next/link'; + import IDataObject from '../interfaces' type Props = { @@ -6,7 +8,9 @@ type Props = { } const ListItem: React.FunctionComponent = ({ data }) => ( - {data.id}:{data.name} + + {data.id}: {data.name} + ); export default ListItem diff --git a/examples/with-typescript/interfaces/index.tsx b/examples/with-typescript/interfaces/index.ts similarity index 100% rename from examples/with-typescript/interfaces/index.tsx rename to examples/with-typescript/interfaces/index.ts diff --git a/examples/with-typescript/pages/about.tsx b/examples/with-typescript/pages/about.tsx index 0e01004b..ed0f797b 100644 --- a/examples/with-typescript/pages/about.tsx +++ b/examples/with-typescript/pages/about.tsx @@ -4,6 +4,7 @@ import Layout from '../components/Layout' const AboutPage: React.FunctionComponent = () => ( +

About

This is the about page

Go home

diff --git a/examples/with-typescript/pages/detail.tsx b/examples/with-typescript/pages/detail.tsx new file mode 100644 index 00000000..f1919d02 --- /dev/null +++ b/examples/with-typescript/pages/detail.tsx @@ -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 { + static getInitialProps = async ({ query }: NextContext) => { + try { + const item = await findData(query.id); + return { item } + } catch (err) { + return { errors: err.message } + } + } + + render() { + const { item, errors } = this.props; + + if (errors) { + return ( + +

Error: {errors}

+
+ ) + } + + return ( + + {item && } + + ) + } +} + +export default ListDetailPage diff --git a/examples/with-typescript/pages/list-class.tsx b/examples/with-typescript/pages/list-class.tsx index 3e290146..20395ae2 100644 --- a/examples/with-typescript/pages/list-class.tsx +++ b/examples/with-typescript/pages/list-class.tsx @@ -1,12 +1,15 @@ -import React from 'react' +import * as React from 'react' import { NextContext } from 'next' +import Link from 'next/link'; import Layout from '../components/Layout' import List from '../components/List' import IDataObject from '../interfaces' +import { findAll } from '../utils/sample-api'; type Props = { items: IDataObject[], + pathname: string, } class ListClass extends React.Component { @@ -14,20 +17,19 @@ class ListClass extends React.Component { // Example for including initial props in a Next.js page. // Don't forget to include the respective types for any // props passed into the component - const dataArray: IDataObject[] = [ - { id: 101, name: 'larry' }, - { id: 102, name: 'sam' }, - { id: 103, name: 'jill' }, - { id: 104, name: pathname }, - ] + const items: IDataObject[] = await findAll() - return { items: dataArray } + return { items, pathname } } render() { + const { items, pathname } = this.props return ( - +

List Example

+

You are currently on: {pathname}

+ +

Go home

) } diff --git a/examples/with-typescript/pages/list-fc.tsx b/examples/with-typescript/pages/list-fc.tsx index 3fd6fe65..3070da66 100644 --- a/examples/with-typescript/pages/list-fc.tsx +++ b/examples/with-typescript/pages/list-fc.tsx @@ -1,15 +1,22 @@ import { NextFunctionComponent, NextContext } from 'next' +import Link from 'next/link'; + import Layout from '../components/Layout' import List from '../components/List' import IDataObject from '../interfaces' +import { findAll } from '../utils/sample-api'; type Props = { items: IDataObject[], + pathname: string, } -const ListFunction: NextFunctionComponent = ({ items }) => ( - +const ListFunction: NextFunctionComponent = ({ items, pathname }) => ( + +

List Example (as Function Component)

+

You are currently on: {pathname}

+

Go home

) @@ -17,14 +24,9 @@ ListFunction.getInitialProps = async ({ pathname }: NextContext) => { // 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 // the component. - const dataArray: IDataObject[] = [ - { id: 101, name: 'larry' }, - { id: 102, name: 'sam' }, - { id: 103, name: 'jill' }, - { id: 104, name: pathname }, - ] + const items: IDataObject[] = await findAll() - return { items: dataArray } + return { items, pathname } } export default ListFunction diff --git a/examples/with-typescript/utils/sample-api.ts b/examples/with-typescript/utils/sample-api.ts new file mode 100644 index 00000000..0c9d21dc --- /dev/null +++ b/examples/with-typescript/utils/sample-api.ts @@ -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 +}