Do A Real Deploy
- Deploy the latest main on shard.homework.quest.
- Try to log in.
Form -> LiveView Demo
(demo was started with)
mix phx.new lvdemo --database sqlite3
cd lvdemo
mix ecto.setup
Let’s look at the demo app from the scratch repo.
Part 1: A Form
In router:
- Path “/form” has a route for both get and post.
- We submit a form, the server can re-render the page.
Part 2: A GenServer
- CommentServer
- Note that it needs to get started from Application
- Demo it with
iex -S mix
Part 3: A Channel + JS
- chan.html.heex
- comment_channel.js (user socket, app.js, etc)
Part 4: A LiveView
- Template, similar to a “dead view”.
- Associated elixir module with callbacks.
- There’s an implicit channel (which is a GenServer) here.
- Page on client is kept in sync with state on server.
- We’re using a .form / .input setup, which would be typical for a deadview too (e.g. it handles _csrf_token).
title: “cs4140 Notes: 19 React” date: “2024-10-04” #
Let’s set up React and a React component for PartyAnimal
cd assets
corepack enable pnpm
pnpm add react
pnpm add flowbite-react
- https://flowbite.com/docs/getting-started/react/
- https://flowbite-react.com/docs/components
- Alt: https://sparkui.vercel.app/?path=/docs/getting-started--docs
Update tailwind config to look in jsx files:
module.exports = {
content: [
"./js/**/*.js",
"./js/**/*.jsx", // Here
In app.js:
import "./invites/main";
In invites/main.jsx:
import React from 'react';
import { createRoot } from 'react-dom/client';
import Invites from './invites';
const root_div = document.getElementById('invites-main');
if (root_div) {
const root = createRoot(root_div);
root.render(<Invites />);
}
In invites/invites.jsx:
import React from 'react';
import { createRoot } from 'react-dom/client';
import { Card } from 'flowbite-react';
export default function Invites(props) {
return (
<div className="flex items-center justify-center">
<Card className="max-w-sm">
<p>Invites go here</p>
</Card>
</div>
);
}
In …/page_html/home.html.heex:
<div id="invites-main">
React component loading...
</div>
In invites/api.js:
const base = "/ajax/invites";
export async function list_invites() {
let resp = await fetch(base, {
headers: {
'Accept': 'application/json',
}
});
return await resp.json();
}
And now update invites.jsx:
import { list_invites } from './api';
export default function Invites(props) {
const [invites, setInvites] = useState([]);
useEffect(() => {
list_invites().then((xs) => setInvites(xs));
}, []);
console.log(invites);
let invite_items = invites.map((item, ii) => (
<li key={ii}>
{ item.name }
</li>
));
return (
<div className="flex items-center justify-center">
<Card className="max-w-sm">
<ul>
{ invite_items }
</ul>
</Card>
</div>
);
}
Digression: Phoenix UI #
We don’t need to push to React just to get already styled UI components: