Skip to content

Commit

Permalink
add new OptimisticMessages component
Browse files Browse the repository at this point in the history
  • Loading branch information
jsoneaday committed Sep 22, 2024
1 parent 76359d3 commit cb41a86
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 19 deletions.
26 changes: 13 additions & 13 deletions Chap5/components/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Chap5/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
"dependencies": {
"@types/react": "npm:types-react@rc",
"@types/react-dom": "npm:types-react-dom@rc",
"react": "19.0.0-rc-5dcb0097-20240918",
"react-dom": "19.0.0-rc-5dcb0097-20240918"
"react": "19.0.0-rc-e4953922-20240919",
"react-dom": "19.0.0-rc-e4953922-20240919"
},
"devDependencies": {
"@eslint/js": "^9.9.0",
Expand Down
3 changes: 2 additions & 1 deletion Chap5/components/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Home, { UserType } from "./Home";
import DeferredValue from "./DeferredValue";
import Transitioner from "./Transitioner";
import UserForm from "./UserForm";
import { OptimisticMessages } from "./OptimisticMessages";

async function fetchData(url: string) {
const response = await fetch(url);
Expand All @@ -26,7 +27,7 @@ function App() {

return (
<>
<UserForm />
<OptimisticMessages />
</>
);
}
Expand Down
6 changes: 6 additions & 0 deletions Chap5/components/src/MessagesData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type Message = { id: number; message: string };

export const messagesOnApi: Message[] = [
{ id: 1, message: "first" },
{ id: 2, message: "second" },
];
83 changes: 83 additions & 0 deletions Chap5/components/src/OptimisticMessages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {
useOptimistic,
useState,
MouseEvent,
ChangeEvent,
useTransition,
useEffect,
} from "react";
import { Message, messagesOnApi } from "./MessagesData";

export function OptimisticMessages() {
const [messagesRetrievedFromApi, setMessagesRetrievedFromApi] = useState<
Message[]
>([]);
const [message, setMessage] = useState("");
const [optimisticMessages, addOptimisticMessage] = useOptimistic<
Message[],
string
>(messagesRetrievedFromApi, (currentMessages, message) => {
const finalMessages = [
...currentMessages,
{ id: getNextId(currentMessages), message },
];
return finalMessages;
});
const [_isPending, startTransition] = useTransition();

useEffect(() => {
const data = JSON.parse(JSON.stringify(messagesOnApi));
setMessagesRetrievedFromApi(data);
}, []);

const addMessage = async (message: string) => {
addOptimisticMessage(message);
await new Promise((res) =>
setTimeout(() => {
messagesOnApi.push({
id: getNextId(messagesOnApi),
message,
});
res(null);
}, 2000)
);

const data = JSON.parse(JSON.stringify(messagesOnApi));
setMessagesRetrievedFromApi(data);
setMessage("");
};

const onChange = (e: ChangeEvent<HTMLInputElement>) => {
e.preventDefault();
setMessage(e.target.value);
};

const onClick = async (e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault();

startTransition(() => {
addMessage(message);
});
};

return (
<div>
<input value={message} onChange={onChange} />
<button onClick={onClick}>add</button>
<ul style={{ listStyleType: "none" }}>
{optimisticMessages.map((m, i) => (
<li key={i}>{m.message}</li>
))}
</ul>
</div>
);
}

function getNextId(currentMessages: Message[]) {
let id = 0;
for (let i = 0; i < currentMessages.length; i++) {
if (currentMessages[i].id > id) id = currentMessages[i].id;
}
id += 1;
return id;
}
11 changes: 11 additions & 0 deletions Chap5/components/src/SubmitButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useFormStatus } from "react-dom";

export default function SubmitButton() {
const { pending } = useFormStatus();

return (
<button type="submit" disabled={pending}>
submit
</button>
);
}
5 changes: 2 additions & 3 deletions Chap5/components/src/UserForm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useActionState } from "react";
import { UserType } from "./Home";
import { users } from "./UserData";
import SubmitButton from "./SubmitButton";

export default function UserForm() {
const [_formState, action, isPending] = useActionState(
Expand Down Expand Up @@ -83,9 +84,7 @@ export default function UserForm() {
</label>
<input id="body" name="body" />
</div>
<button type="submit" disabled={isPending}>
submit
</button>
<SubmitButton />
{JSON.stringify(users)}
</form>
);
Expand Down

0 comments on commit cb41a86

Please sign in to comment.