Files
cerebellum.neuroinf.jp/src/database/DatabaseDetailItem.tsx
T
orrisroot a14bc6dd4b feat: migrate from Create React App to Vite
react-scripts 4 on React 17 no longer builds on a current toolchain.
Move to Vite 8 with React 19 and TypeScript 7, and take the same
shape the other two converted sites settled on.

- react-router-dom v5 -> react-router v8: Switch/Redirect become
  Routes/Navigate, and withRouter and RouteComponentProps give way to
  useParams, useLocation and useNavigate
- swap the unmaintained dependencies: axios -> ky, react-html-parser
  -> @orrisroot/react-html-parser, react-ga -> react-ga4,
  react-helmet -> @dr.pogodin/react-helmet, react-image-lightbox ->
  yet-another-react-lightbox, moment -> date-fns, and a local
  HashLink in place of react-router-hash-link
- drop react-app-polyfill, the jest setup and xregexp
- replace ESLint with Biome, and match the other sites' tsconfigs
- serve the dumped JSON from static-contents/modules/ at runtime
  instead of compiling it into the bundle, and mount that directory
  with sirv in both the dev and preview servers
- lazy-load NewArticleAlert: at 342 kB of static bibliography it is
  the largest file in the app and only ever renders on the top page,
  which cuts the entry chunk from 580 kB to 200 kB
- restate the theme sizes the modules/ move and border-box need, and
  keep the browser's own font on form controls
- set the GA4 measurement ID replacing the shut-down UA property
- write down the deployment procedure
2026-09-11 21:25:39 +09:00

65 lines
2.0 KiB
TypeScript

import { Helmet } from '@dr.pogodin/react-helmet';
import { useEffect, useState } from 'react';
import { useParams } from 'react-router';
import Loading from '../common/lib/Loading';
import PageNotFound from '../common/lib/PageNotFound';
import type { MultiLang } from '../config';
import Functions from '../functions';
import ItemType from './item-type';
import ItemUtil, { type Item } from './lib/ItemUtil';
interface Props {
lang: MultiLang;
}
const DatabaseDetailItem = (props: Props) => {
const { lang } = props;
const params = useParams<{ id?: string; doi?: string }>();
const id = typeof params.id !== 'undefined' ? (params.id.match(/^\d+$/) !== null ? parseInt(params.id, 10) : 0) : 0;
const doi = params.doi ?? '';
const [loading, setLoading] = useState(true);
const [item, setItem] = useState<Item | null>(null);
useEffect(() => {
let active = true;
const receive = (found: Item | null) => {
if (active) {
setItem(found);
setLoading(false);
}
};
if (doi !== '') {
ItemUtil.getByDoi(doi, receive);
} else if (id !== 0) {
ItemUtil.get(id, receive);
} else {
receive(null);
}
return () => {
active = false;
};
}, [id, doi]);
if (loading) {
return <Loading />;
}
if (item === null) {
return <PageNotFound lang={lang} />;
}
return (
<>
<Helmet>
<title>
{Functions.mlang(item.title, lang)} -{' '}
{Functions.mlang('[en]Database[/en][ja]データベース[/ja]', lang)} - {Functions.siteTitle(lang)}
</title>
</Helmet>
<h3>{Functions.mlang('[en]Item Detail[/en][ja]アイテム詳細[/ja]', lang)}</h3>
<br />
<ItemType.Detail lang={lang} item={item} />
</>
);
};
export default DatabaseDetailItem;