Skip to content

Commit

Permalink
example: fix typescript type and use loader to ensure data is loaded (#…
Browse files Browse the repository at this point in the history
…16)

* fix: 修复 TypeScript 类型问题

* example: Resolved TypeScript type and Using Loaders to ensure data is loaded
  • Loading branch information
Wu-kung authored Nov 7, 2024
1 parent b53599a commit e893412
Show file tree
Hide file tree
Showing 18 changed files with 199 additions and 110 deletions.
18 changes: 13 additions & 5 deletions examples/hackernews/src/components/comment/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,19 @@ import { fetchItem } from '../../services';
import { pluralize, timeAgo } from '../../utils';
import styles from './index.module.less';

export default function Comment({ id, itemsById }) {
interface CommentProps {
id: number;
}

interface CommentType {
by: string;
time: number;
text: string;
kids?: number[];
}
export default function Comment({ id }: CommentProps) {
const [open, setOpen] = useState(true);
const [comment, setComment] = useState(null);
const [comment, setComment] = useState<CommentType | null>(null);

useEffect(() => {
async function fetchComments() {
Expand Down Expand Up @@ -45,9 +55,7 @@ export default function Comment({ id, itemsById }) {
/>
<div className={styles.commentChildren}>
{comment.kids && open
? comment.kids.map((id) => (
<Comment key={id} id={id} itemsById={itemsById} />
))
? comment.kids.map((id) => <Comment key={id} id={id} />)
: null}
</div>
</div>
Expand Down
63 changes: 21 additions & 42 deletions examples/hackernews/src/components/item-list/index.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,29 @@
import { useContext, useEffect, useMemo, useState } from 'react';
import { Link } from '@umijs/tnf/router';
import { Context } from '../../context';
import { fetchIdsByType, fetchItems } from '../../services';
import React, { Link } from '@umijs/tnf/router';
import type { ItemProps } from '../../types';
import Item from '../item';
import Loading from '../loading';
import styles from './index.module.less';

export default function ItemList({ type, page }) {
const { dispatch } = useContext(Context);
const [lists, setLists] = useState({
top: [],
new: [],
show: [],
ask: [],
job: [],
});
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);

const itemsPerPage = 20;
const maxPage = useMemo(
() => Math.ceil(lists[type].length / itemsPerPage),
[lists],
);

useEffect(() => {
async function fetchList() {
const ids = await fetchIdsByType(type);
setLists({ ...lists, [type]: ids });
const items = await fetchItems(
ids.slice(itemsPerPage * (page - 1), itemsPerPage * page),
);
const itemsById = items.reduce((_memo, item) => {
const memo = _memo;
memo[item.id] = item;
return memo;
}, {});
setLoading(false);
setItems(items);
dispatch({ type: 'saveItems', payload: itemsById });
}
interface ItemListProps {
type: keyof Lists;
page: number;
maxPage: number;
items: ItemProps[];
}

fetchList();
}, [page]);
interface Lists {
top: number[];
new: number[];
show: number[];
ask: number[];
job: number[];
}

export default function ItemList({
type,
items,
page,
maxPage,
}: ItemListProps) {
return (
<>
<div className={styles.nav}>
Expand All @@ -65,7 +45,6 @@ export default function ItemList({ type, page }) {
</div>

<div className={styles.list}>
<Loading loading={loading} />
{items.map((item) => (
<Item key={item.id} item={item} />
))}
Expand Down
9 changes: 4 additions & 5 deletions examples/hackernews/src/components/item-page/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Link } from '@umijs/tnf/router';
import React, { Link } from '@umijs/tnf/router';
import type { ItemProps } from '../../types';
import { host, timeAgo } from '../../utils';
import Comment from '../comment';
import styles from './index.module.less';

export default function ItemPage({ item, itemsById }) {
export default function ItemPage({ item }: { item: ItemProps }) {
if (!item) return null;
return (
<>
Expand All @@ -26,9 +27,7 @@ export default function ItemPage({ item, itemsById }) {
</p>
<div className={styles.commentChildren}>
{item.kids
? item.kids.map((id) => (
<Comment key={id} id={id} itemsById={itemsById} />
))
? item.kids.map((id) => <Comment key={id} id={id} />)
: null}
</div>
</div>
Expand Down
19 changes: 16 additions & 3 deletions examples/hackernews/src/components/item/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
import { Link } from '@umijs/tnf/router';
import React, { Link } from '@umijs/tnf/router';
import { host, timeAgo } from '../../utils';
import styles from './index.module.less';

export default function Item({ item }) {
interface ItemProps {
item: {
score: number;
title: string;
url?: string;
type: string;
id: number;
by: string;
descendants: number;
time: number;
};
}

export default function Item({ item }: ItemProps) {
const { score, title, url, type, id, by, descendants, time } = item;

return (
Expand All @@ -17,7 +30,7 @@ export default function Item({ item }) {
<span className={styles.host}> ({host(url)})</span>
</span>
) : (
<Link to={`/item/$id`} params={{ id }} state={{ item }}>
<Link to={`/item/$id`} params={{ id }}>
{title}
</Link>
)}
Expand Down
11 changes: 8 additions & 3 deletions examples/hackernews/src/components/loading/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import React from 'react';
import classnames from 'classnames';
import styles from './index.module.less';

function Spinner({ loading }) {
interface SpinnerProps {
loading: boolean;
}

function Spinner({ loading }: SpinnerProps) {
const svgCls = classnames({
[styles.spinner]: true,
[styles.show]: loading,
[styles.spinner as string]: true,
[styles.show as string]: loading,
});
return (
<div>
Expand Down
16 changes: 9 additions & 7 deletions examples/hackernews/src/components/user-page/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { useEffect, useState } from 'react';
import { fetchUser } from '../../services';
import React from 'react';
import { timeAgo } from '../../utils';
import styles from './index.module.less';

export default function UserPage({ id }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(id).then((user) => setUser(user));
}, []);
interface User {
id: string;
created: number;
karma: number;
about?: string;
}

export default function UserPage({ user }: { user: User }) {
if (!user) return null;
return (
<div className={styles.normal}>
Expand Down
17 changes: 0 additions & 17 deletions examples/hackernews/src/context/index.tsx

This file was deleted.

9 changes: 2 additions & 7 deletions examples/hackernews/src/pages/__root.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import React, { useReducer } from 'react';
import { Link, Outlet, createRootRoute } from '@umijs/tnf/router';
import { Context, initialState, reducer } from '../context';
import React, { Link, Outlet, createRootRoute } from '@umijs/tnf/router';
import '../global.less';
import styles from './index.module.less';

export const Route = createRootRoute({
component: () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
<div className={styles.header}>
Expand Down Expand Up @@ -66,9 +63,7 @@ export const Route = createRootRoute({
</div>
</div>
<div className={styles.view}>
<Context.Provider value={{ state, dispatch }}>
<Outlet />
</Context.Provider>
<Outlet />
</div>
</>
);
Expand Down
10 changes: 9 additions & 1 deletion examples/hackernews/src/pages/ask/$page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import React, { createFileRoute } from '@umijs/tnf/router';
import ItemList from '../../components/item-list';
import { fetchList } from '../../services/api';
import type { Params } from '../../types';

export const Route = createFileRoute('/ask/$page')({
component: AskComponent,
loader: async ({ params }: { params: Params }) =>
await fetchList('ask', Number(params.page)),
});

function AskComponent() {
const { page } = Route.useParams();
return <ItemList type="ask" page={Number(page)} />;
const { items, maxPage } = Route.useLoaderData();

return (
<ItemList type="ask" page={Number(page)} maxPage={maxPage} items={items} />
);
}
12 changes: 9 additions & 3 deletions examples/hackernews/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { createFileRoute } from '@umijs/tnf/router';
import React, { createFileRoute } from '@umijs/tnf/router';
import ItemList from '../components/item-list';
import { fetchList } from '../services/api';
import type { Params } from '../types';

export const Route = createFileRoute('/')({
component: TopComponent,
loader: async ({ params }: { params: Params }) =>
await fetchList('top', Number(params?.page ?? '1') ?? 1),
});

function TopComponent() {
const page = Number(Route.useParams()?.page ?? '1') ?? 1;
const params = Route.useParams<Params>();
const page = Number(params?.page ?? '1') ?? 1;
const { items, maxPage } = Route.useLoaderData();

return <ItemList type="top" page={page} />;
return <ItemList type="top" page={page} maxPage={maxPage} items={items} />;
}
14 changes: 6 additions & 8 deletions examples/hackernews/src/pages/item/$itemId.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import React, { useContext } from 'react';
import { createFileRoute } from '@umijs/tnf/router';
import React, { createFileRoute } from '@umijs/tnf/router';
import ItemPage from '../../components/item-page';
import { Context } from '../../context';
import { fetchItem } from '../../services';

export const Route = createFileRoute('/item/$itemId')({
component: Item,
loader: async ({ params }: { params: { itemId: string } }) =>
await fetchItem(params.itemId),
});

function Item() {
const { itemId } = Route.useParams();
const { state } = useContext(Context);
return (
<ItemPage item={state.itemsById[itemId]} itemsById={state.itemsById} />
);
const item = Route.useLoaderData();
return <ItemPage item={item} />;
}
10 changes: 9 additions & 1 deletion examples/hackernews/src/pages/job/$page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import React, { createFileRoute } from '@umijs/tnf/router';
import ItemList from '../../components/item-list';
import { fetchList } from '../../services/api';
import type { Params } from '../../types';

export const Route = createFileRoute('/job/$page')({
component: JobComponent,
loader: async ({ params }: { params: Params }) =>
await fetchList('job', Number(params.page)),
});

function JobComponent() {
const { page } = Route.useParams();
return <ItemList type="job" page={Number(page)} />;
const { items, maxPage } = Route.useLoaderData();

return (
<ItemList type="job" page={Number(page)} maxPage={maxPage} items={items} />
);
}
10 changes: 9 additions & 1 deletion examples/hackernews/src/pages/new/$page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import React, { createFileRoute } from '@umijs/tnf/router';
import ItemList from '../../components/item-list';
import { fetchList } from '../../services/api';
import type { Params } from '../../types';

export const Route = createFileRoute('/new/$page')({
component: NewComponent,
loader: async ({ params }: { params: Params }) =>
await fetchList('new', Number(params.page)),
});

function NewComponent() {
const { page } = Route.useParams();
return <ItemList type="new" page={Number(page)} />;
const { items, maxPage } = Route.useLoaderData();

return (
<ItemList type="new" page={Number(page)} maxPage={maxPage} items={items} />
);
}
10 changes: 9 additions & 1 deletion examples/hackernews/src/pages/show/$page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import React, { createFileRoute } from '@umijs/tnf/router';
import ItemList from '../../components/item-list';
import { fetchList } from '../../services/api';
import type { Params } from '../../types';

export const Route = createFileRoute('/show/$page')({
component: ShowComponent,
loader: async ({ params }: { params: Params }) =>
await fetchList('show', Number(params.page)),
});

function ShowComponent() {
const { page } = Route.useParams();
return <ItemList type="show" page={Number(page)} />;
const { items, maxPage } = Route.useLoaderData();

return (
<ItemList type="show" page={Number(page)} maxPage={maxPage} items={items} />
);
}
Loading

0 comments on commit e893412

Please sign in to comment.