Use suspense / error boundary
This commit is contained in:
@@ -6,16 +6,13 @@ import StringFilter from "./components/StringFilter/StringFilter";
|
||||
import useGlossary from "./hooks/useGlossary";
|
||||
|
||||
function App() {
|
||||
const { glossary, citations, isLoading, isError } = useGlossary();
|
||||
const { glossary, citations } = useGlossary();
|
||||
|
||||
const [alphabeticalFilter, setAlphabeticalFilter] = useState("");
|
||||
const [stringFilter, setStringFilter] = useState("");
|
||||
const [selectedCitation, setSelectedCitation] = useState<string | null>(null);
|
||||
|
||||
if (isLoading) return <div>Loading...</div>;
|
||||
if (isError) return <div>Error while fetching</div>;
|
||||
|
||||
const entries = glossary!
|
||||
const entries = glossary
|
||||
.filter((entry) => {
|
||||
if (!stringFilter) {
|
||||
return true;
|
||||
@@ -40,7 +37,7 @@ function App() {
|
||||
{selectedCitation && (
|
||||
<CitationEntry
|
||||
citation={
|
||||
citations!.find((citation) => citation.key === selectedCitation)!
|
||||
citations.find((citation) => citation.key === selectedCitation)!
|
||||
}
|
||||
onClose={() => setSelectedCitation(null)}
|
||||
/>
|
||||
|
||||
9
src/components/ErrorBoundary/ErrorBoundary.css
Normal file
9
src/components/ErrorBoundary/ErrorBoundary.css
Normal file
@@ -0,0 +1,9 @@
|
||||
.error-boundary {
|
||||
color: red;
|
||||
font-size: 1.2rem;
|
||||
text-align: center;
|
||||
|
||||
pre {
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
43
src/components/ErrorBoundary/ErrorBoundary.tsx
Normal file
43
src/components/ErrorBoundary/ErrorBoundary.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import type { ReactNode } from "react";
|
||||
import React, { Component } from "react";
|
||||
|
||||
import "./ErrorBoundary.css";
|
||||
|
||||
interface ErrorBoundaryProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
interface ErrorBoundaryState {
|
||||
hasError: boolean;
|
||||
error: Error | null;
|
||||
}
|
||||
|
||||
class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
||||
constructor(props: ErrorBoundaryProps) {
|
||||
super(props);
|
||||
this.state = { hasError: false, error: null };
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error: Error) {
|
||||
return { hasError: true, error };
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
componentDidCatch(_: Error, __: React.ErrorInfo) {
|
||||
// You can log the error to an error reporting service here
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<div className="error-boundary">
|
||||
<h2>Something went wrong.</h2>
|
||||
<pre>{this.state.error?.message}</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
export default ErrorBoundary;
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||
import { fetchCitations, fetchDefinitions } from "../lib/nist-api";
|
||||
|
||||
const useGlossary = () => {
|
||||
const definitionsQuery = useQuery({
|
||||
const definitionsQuery = useSuspenseQuery({
|
||||
queryKey: ["definitions"],
|
||||
queryFn: fetchDefinitions,
|
||||
staleTime: 1000 * 60 * 60, // 1 hour
|
||||
});
|
||||
const citationsQuery = useQuery({
|
||||
const citationsQuery = useSuspenseQuery({
|
||||
queryKey: ["citations"],
|
||||
queryFn: fetchCitations,
|
||||
staleTime: 1000 * 60 * 60, // 1 hour
|
||||
@@ -16,8 +16,6 @@ const useGlossary = () => {
|
||||
return {
|
||||
glossary: definitionsQuery.data,
|
||||
citations: citationsQuery.data,
|
||||
isLoading: definitionsQuery.isLoading || citationsQuery.isLoading,
|
||||
isError: definitionsQuery.isError || citationsQuery.isError,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ const citationGid = "2053825396";
|
||||
const makeClient = () => {
|
||||
const client = new Axios({
|
||||
baseURL: baseUrl,
|
||||
timeout: 2500,
|
||||
});
|
||||
return client;
|
||||
};
|
||||
@@ -62,18 +63,6 @@ export const fetchDefinitions = async () => {
|
||||
return parseDefinitions(resp.data);
|
||||
};
|
||||
|
||||
export const parseGlossary = (
|
||||
glossaryData: string,
|
||||
citationData: string
|
||||
): Glossary => {
|
||||
const glossary: Glossary = {
|
||||
definitions: parseDefinitions(glossaryData),
|
||||
citations: parseCitations(citationData),
|
||||
};
|
||||
|
||||
return glossary;
|
||||
};
|
||||
|
||||
const parseDefinitions = (glossaryData: string): GlossaryTerm[] => {
|
||||
const terms: GlossaryTerm[] = [];
|
||||
const parsed = Papa.parse<string[]>(glossaryData, {
|
||||
|
||||
13
src/main.tsx
13
src/main.tsx
@@ -1,15 +1,26 @@
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||
import { StrictMode } from "react";
|
||||
import { StrictMode, Suspense } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import App from "./App.tsx";
|
||||
import ErrorBoundary from "./components/ErrorBoundary/ErrorBoundary";
|
||||
import "./index.css";
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<StrictMode>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ErrorBoundary>
|
||||
<Suspense
|
||||
fallback={
|
||||
<div style={{ textAlign: "center", marginTop: "2rem" }}>
|
||||
Loading...
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<App />
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
<ReactQueryDevtools initialIsOpen={false} />
|
||||
</QueryClientProvider>
|
||||
</StrictMode>
|
||||
|
||||
Reference in New Issue
Block a user