Skip to content

Commit 672ced4

Browse files
authored
Integrate useTransition Hook for Optimized State Transitions (#157)
Implementing useTransition hook with async
1 parent 21a6be0 commit 672ced4

File tree

7 files changed

+91
-110
lines changed

7 files changed

+91
-110
lines changed

Diff for: packages/frontend/src/components/ButtonSpinner.tsx

+1-8
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,7 @@ import React from "react";
22
import { Spinner } from "react-bootstrap";
33

44
const ButtonSpinner = () => (
5-
<Spinner
6-
as="span"
7-
animation="border"
8-
size="sm"
9-
role="status"
10-
aria-hidden="true"
11-
className="mr-1"
12-
/>
5+
<Spinner as="span" animation="border" size="sm" role="status" aria-hidden="true" className="mr-1" />
136
);
147

158
export { ButtonSpinner };

Diff for: packages/frontend/src/components/PageContainer.tsx

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import React from "react";
22
import { Card } from "react-bootstrap";
33

4-
const PageContainer = (props: {
5-
header: React.ReactNode;
6-
children: React.ReactNode;
7-
}) => (
4+
const PageContainer = (props: { header: React.ReactNode; children: React.ReactNode }) => (
85
<Card>
96
<Card.Header>{props.header}</Card.Header>
107
<Card.Body>{props.children}</Card.Body>

Diff for: packages/frontend/src/content/CreateNote.tsx

+19-22
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, FormEvent } from "react";
1+
import React, { useState, FormEvent, useTransition } from "react";
22
import { Form, Button, Alert } from "react-bootstrap";
33
import { navigate, RouteComponentProps } from "@reach/router";
44
import { GATEWAY_URL } from "../config";
@@ -10,7 +10,7 @@ import { PlayAudioButton } from "./PlayAudioButton";
1010
const MAX_FILE_SIZE = 2000000;
1111

1212
const CreateNote = (props: RouteComponentProps) => {
13-
const [isLoading, setIsLoading] = useState(false);
13+
const [isPending, startTransition] = useTransition();
1414
const [errorMsg, setErrorMsg] = useState("");
1515
const [noteContent, setNoteContent] = useState("");
1616
const [file, setFile] = useState();
@@ -26,24 +26,21 @@ const CreateNote = (props: RouteComponentProps) => {
2626
setErrorMsg(`File can't be bigger than ${MAX_FILE_SIZE / 1000000} MB`);
2727
return;
2828
}
29+
startTransition(async () => {
30+
const createNoteURL = `${GATEWAY_URL}notes`;
2931

30-
setIsLoading(true);
31-
32-
const createNoteURL = `${GATEWAY_URL}notes`;
33-
34-
try {
35-
// @ts-ignore Argument of type 'undefined' is not assignable to parameter of type 'File'
36-
const attachment = file ? await putObject(file) : undefined;
37-
await fetch(createNoteURL, {
38-
method: "POST",
39-
body: JSON.stringify({ attachment, content: noteContent }),
40-
});
41-
navigate("/");
42-
} catch (error) {
43-
setErrorMsg(`${error.toString()} - ${createNoteURL} - ${noteContent}`);
44-
} finally {
45-
setIsLoading(false);
46-
}
32+
try {
33+
// @ts-ignore Argument of type 'undefined' is not assignable to parameter of type 'File'
34+
const attachment = file ? await putObject(file) : undefined;
35+
await fetch(createNoteURL, {
36+
method: "POST",
37+
body: JSON.stringify({ attachment, content: noteContent }),
38+
});
39+
navigate("/");
40+
} catch (error) {
41+
setErrorMsg(`${error.toString()} - ${createNoteURL} - ${noteContent}`);
42+
}
43+
});
4744
};
4845

4946
const noteContentAdditionalProps = isRecording || isPlaying ? { disabled: true, value: noteContent } : {};
@@ -90,9 +87,9 @@ const CreateNote = (props: RouteComponentProps) => {
9087
type="file"
9188
/>
9289
</Form.Group>
93-
<Button type="submit" disabled={!noteContent || isLoading} block>
94-
{isLoading ? <ButtonSpinner /> : ""}
95-
{isLoading ? "Creating..." : "Create"}
90+
<Button type="submit" disabled={!noteContent || isPending} block>
91+
{isPending ? <ButtonSpinner /> : ""}
92+
{isPending ? "Creating..." : "Create"}
9693
</Button>
9794
</form>
9895
</PageContainer>

Diff for: packages/frontend/src/content/DeleteNoteButton.tsx

+16-18
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState } from "react";
1+
import React, { useState, useTransition } from "react";
22
import { Button, Alert } from "react-bootstrap";
33
import { GATEWAY_URL } from "../config";
44
import { navigate } from "@reach/router";
@@ -7,28 +7,26 @@ import { ButtonSpinner } from "../components";
77

88
const DeleteNoteButton = (props: { noteId: string; attachment?: string }) => {
99
const { noteId, attachment } = props;
10-
const [isDeleting, setIsDeleting] = useState(false);
10+
const [isDeleting, startTransition] = useTransition();
1111
const [errorMsg, setErrorMsg] = useState("");
1212

13-
const handleDelete = async (event: any) => {
13+
const handleDelete = (event: React.MouseEvent<HTMLButtonElement>) => {
1414
event.preventDefault();
15-
setIsDeleting(true);
15+
startTransition(async () => {
16+
const deleteNoteURL = `${GATEWAY_URL}notes/${noteId}`;
1617

17-
const deleteNoteURL = `${GATEWAY_URL}notes/${noteId}`;
18-
19-
try {
20-
if (attachment) {
21-
await deleteObject(attachment);
18+
try {
19+
if (attachment) {
20+
await deleteObject(attachment);
21+
}
22+
await fetch(deleteNoteURL, {
23+
method: "DELETE",
24+
});
25+
navigate("/");
26+
} catch (error) {
27+
setErrorMsg(`${error.toString()} - ${deleteNoteURL} - ${noteId}`);
2228
}
23-
await fetch(deleteNoteURL, {
24-
method: "DELETE",
25-
});
26-
navigate("/");
27-
} catch (error) {
28-
setErrorMsg(`${error.toString()} - ${deleteNoteURL} - ${noteId}`);
29-
} finally {
30-
setIsDeleting(false);
31-
}
29+
});
3230
};
3331

3432
return (

Diff for: packages/frontend/src/content/ListNotes.tsx

+15-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect } from "react";
1+
import React, { useState, useTransition, useEffect } from "react";
22
import { Link, RouteComponentProps } from "@reach/router";
33
import { GATEWAY_URL } from "../config";
44
import { Card, Alert, CardColumns, Button } from "react-bootstrap";
@@ -11,24 +11,23 @@ interface Note {
1111
}
1212

1313
const ListNotes = (props: RouteComponentProps) => {
14-
const [isLoading, setIsLoading] = useState(true);
14+
const [isPending, startTransition] = useTransition();
1515
const [errorMsg, setErrorMsg] = useState("");
16-
const [notes, setNotes] = useState([]);
16+
const [notes, setNotes] = useState<Note[]>([]);
1717

1818
useEffect(() => {
19-
const fetchNotes = async () => {
20-
setIsLoading(true);
21-
const fetchURL = `${GATEWAY_URL}notes`;
19+
const fetchNotes = () => {
20+
startTransition(async () => {
21+
const fetchURL = `${GATEWAY_URL}notes`;
2222

23-
try {
24-
const response = await fetch(fetchURL);
25-
const data = await response.json();
26-
setNotes(data);
27-
} catch (error) {
28-
setErrorMsg(`${error.toString()} - ${fetchURL}`);
29-
} finally {
30-
setIsLoading(false);
31-
}
23+
try {
24+
const response = await fetch(fetchURL);
25+
const data = await response.json();
26+
setNotes(data);
27+
} catch (error) {
28+
setErrorMsg(`${error.toString()} - ${fetchURL}`);
29+
}
30+
});
3231
};
3332
fetchNotes();
3433
}, []);
@@ -65,7 +64,7 @@ const ListNotes = (props: RouteComponentProps) => {
6564
return (
6665
<PageContainer header={<div>Your Notes</div>}>
6766
{errorMsg && <Alert variant="danger">{errorMsg}</Alert>}
68-
{isLoading ? (
67+
{isPending ? (
6968
<Loading />
7069
) : (
7170
<div>

Diff for: packages/frontend/src/content/SaveNoteButton.tsx

+19-21
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,38 @@
1-
import React, { useState } from "react";
1+
import React, { useState, useTransition } from "react";
22
import { Button, Alert } from "react-bootstrap";
33
import { GATEWAY_URL } from "../config";
44
import { navigate } from "@reach/router";
55
import { ButtonSpinner } from "../components";
66

77
const SaveNoteButton = (props: { noteId: string; noteContent: string }) => {
8-
const [isSaving, setIsSaving] = useState(false);
8+
const [isPending, startTransition] = useTransition();
99
const [errorMsg, setErrorMsg] = useState("");
1010

1111
const handleSave = async (event: any) => {
1212
event.preventDefault();
13-
setIsSaving(true);
13+
startTransition(async () => {
14+
const { noteId, noteContent } = props;
15+
const updateNoteURL = `${GATEWAY_URL}notes/${noteId}`;
1416

15-
const { noteId, noteContent } = props;
16-
const updateNoteURL = `${GATEWAY_URL}notes/${noteId}`;
17-
18-
try {
19-
await fetch(updateNoteURL, {
20-
method: "PUT",
21-
body: JSON.stringify({ content: noteContent }),
22-
});
23-
navigate("/");
24-
} catch (error) {
25-
console.log(error);
26-
setErrorMsg(`${error.toString()} - ${updateNoteURL} - ${noteContent}`);
27-
} finally {
28-
setIsSaving(false);
29-
}
17+
try {
18+
await fetch(updateNoteURL, {
19+
method: "PUT",
20+
body: JSON.stringify({ content: noteContent }),
21+
});
22+
navigate("/");
23+
} catch (error) {
24+
console.log(error);
25+
setErrorMsg(`${error.toString()} - ${updateNoteURL} - ${noteContent}`);
26+
}
27+
});
3028
};
3129

3230
return (
3331
<>
3432
{errorMsg && <Alert variant="danger">{errorMsg}</Alert>}
35-
<Button disabled={isSaving} onClick={handleSave} block>
36-
{isSaving ? <ButtonSpinner /> : ""}
37-
{isSaving ? "Saving..." : "Save"}
33+
<Button disabled={isPending} onClick={handleSave} block>
34+
{isPending ? <ButtonSpinner /> : ""}
35+
{isPending ? "Saving..." : "Save"}
3836
</Button>
3937
</>
4038
);

Diff for: packages/frontend/src/content/ShowNote.tsx

+20-21
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect } from "react";
1+
import React, { useState, useEffect, useTransition } from "react";
22
import { RouteComponentProps, navigate } from "@reach/router";
33
import { Form, Card } from "react-bootstrap";
44
import { GATEWAY_URL } from "../config";
@@ -8,37 +8,36 @@ import { HomeButton, Loading, PageContainer } from "../components";
88

99
const ShowNote = (props: RouteComponentProps<{ noteId: string }>) => {
1010
const { noteId } = props;
11-
const [isLoading, setIsLoading] = useState(true);
11+
const [isPending, startTransition] = useTransition();
1212
const [noteContent, setNoteContent] = useState("");
1313
const [attachment, setAttachment] = useState("");
1414
const [attachmentURL, setAttachmentURL] = useState("");
1515

16+
1617
useEffect(() => {
17-
const fetchNote = async (noteId: string) => {
18-
setIsLoading(true);
19-
const fetchURL = `${GATEWAY_URL}notes/${noteId}`;
18+
if (noteId) {
19+
startTransition(async () => {
20+
const fetchURL = `${GATEWAY_URL}notes/${noteId}`;
2021

21-
try {
22-
const response = await fetch(fetchURL);
23-
const data = await response.json();
24-
setNoteContent(data.content);
25-
if (data.attachment) {
26-
setAttachment(data.attachment);
27-
setAttachmentURL(await getObjectUrl(data.attachment));
22+
try {
23+
const response = await fetch(fetchURL);
24+
const data = await response.json();
25+
setNoteContent(data.content);
26+
if (data.attachment) {
27+
setAttachment(data.attachment);
28+
setAttachmentURL(await getObjectUrl(data.attachment));
29+
}
30+
} catch (error) {
31+
// Navigate to 404 page, as noteId probably not present
32+
navigate("/404");
2833
}
29-
} catch (error) {
30-
// Navigate to 404 page, as noteId probably not present
31-
navigate("/404");
32-
} finally {
33-
setIsLoading(false);
34-
}
35-
};
36-
fetchNote(noteId || "");
34+
});
35+
}
3736
}, [noteId]);
3837

3938
return (
4039
<PageContainer header={<HomeButton />}>
41-
{isLoading ? (
40+
{isPending ? (
4241
<Loading />
4342
) : (
4443
<form>

0 commit comments

Comments
 (0)