Transcript
This transcript was autogenerated. To make changes, submit a PR.
Jamaica make a real
time feedback into the behavior of your distributed systems
and observing changes, exceptions,
errors in real time allows youre to not only experiment with confidence
but respond instantly to get things working again.
Close hi
everybody, I'm dave bitter. I'm a developer advocate working at IO in the Netherlands
and today I want to have a look with you at Remix, the new
full stack web framework. So what does remix
do? How does it work? Why should you use it? We're going
to cover everything in the next 35 minutes and have a look together at
web fundamentals, which is always a very good thing to do
between developers. So let's get started.
So remix is a full stack web framework,
emphasis on the web part based on web fundamentals.
So it will have both client and server side
and it's going to try to use web fundamentals to
smartly talk between the two of them and to help
you really leverage the browser, leverage the web as a
platform instead of working against it. But Remix
is also a framework to build over encountered websites.
So this is what somebody tweeted me. I anonymized their data here after
I got so excited about Remix and I shared something on Twitter.
So this is pretty standard. When you post something
on Twitter you will get these comments. But it was an
interesting discussion and a perfect way to add an intro to
my entire talk. So let's call him a
guy on the Internet said well, remix is a framework to build over engineered
websites and you appear to not know the difference between a website,
a place on the Internet with a URL and an app, a standalone
program on a mobile device. And I mean,
I don't blame him. There are two different platforms,
but are they so different nowadays?
Especially since he tweeted this from the Twitter web
app? And the lines between
these websites and applications got so blurry over time
that it's hard to sometimes spot the difference and which pattern should you
use when?
So naturally I reacted and told them, well,
basically remix is actually really good
against over engineering because it goes back to web fundamentals,
right? It's leveraging what the browser already offers for you and
you can then use that to build your website for the platform you're actually
developing on the web.
So basically it's a major shift in how we think
about building for the web. So first we cover all
our bases with web fundamentals, then we use progressive enhancement to
build layer by layer and in the end have a
full blown application where every layer of
progressive enhancement is supported correctly, where we have basically
the good old of the web but then up to par with modern
Ux. Of course
this Twitter beef continued, and I'm still talking about
web apps, there's no such things. Website have a URL, apps are standalone.
Well we covered this of course with the Twitter web app example, but he
says you can try meshing them together and that will inevitably fill
being good at one or the other. And here I sort of kind of
agree, right. If you really try to get all these native
patterns on the web, you might have to do some weird stuff and
it doesn't work well. But what I noticed, what I've been
doing, and people around me is sometimes really
not embracing the platform we are building for which is the web,
which is incredibly powerful and often overlooked.
And naturally you never want to lose an Internet argument.
So yeah, for instance, we have progressive web apps, right, where we can then
have an app, but again, this is an enhancement.
We have a basic layer, we build our website out and then
we can always enhance further. And that's something really
nice that the web offers, of course. But tell me you're frustrated
by all these frameworks without telling me you're frustrated, right?
And I fouls feel the pain. It's every time a new framework pops
up and I wanted to give this talk because
I really believe in remix as a framework, at least what they stand for,
to basically offer you the web fundamentals and then tools
to be up to par with modern Ux.
Because sometimes it feels a bit like this, right? You have that friend who says
well you should totally come to the party, it's going to be great, should see
the lineup and this, and this person is going to be there, it's all good
vibes. And you start thinking like, oh well maybe I need to
really check this out. So this is what new frameworks often look like
or feel like rather. And you get fomo, right? It's like,
oh, am I still relevant if I don't pick up this framework? And I think
that's an inherent thing about all these frameworks, is if
you keep on reinventing the wheel, you have to keep on learning
all these different new patterns. While learning a framework
that uses web fundamentals will give you a solid base to
work on the web in general. And hopefully more frameworks
will pick up on this because usually when you use a framework,
you run into the same issues that you had the last time you used
a new framework. So I have an arbitrary amount of examples here,
like complex state and it's like sure your readme works
perfectly fine, but I got really complex state and I need to keep my data
up to date and there are non standards being used.
And this to me is then where remix comes in by
using the web standards and using that to build around.
So web fundamentals, enhance them with
modern ux.
This is a logo I think we all know, especially during the pandemic.
We spent a lot of time on Microsoft Teams and it
basically replaced every normal communication that we had with each
other, but also our processes in development. So if you work in
an agile environment, you have probably worked with
Microsoft Teams to then do scrum sessions.
Well, those are usually pretty interactive, which is nice about those sessions.
But what we also needed to do was, for instance,
give an effort to new tasks,
right? There's a new task, it's been refined and everything.
And now we say, okay, well I'm going to give it one, three, five,
whatever system you use, we give it so much points and
then we use that for our sprint planning. Well, how we did it now,
because we were all remote, we sort of threw our hands up
in the air, which everything above ten points is really awkward to
do, but spotty connections, people didn't have it
directly in view, so it became all the real
quick, basically. So I was looking at, okay, can we just have an online
application where we can do this? Turns out there are a lot of applications
that allow you to do scrum poker sessions online. But hey,
I'm a developer, I'll build it myself. Right.
And this is a perfect thing to really put remix to the test
because. Yeah, I get it. You go to the remix page,
there's a readme there, it's a super basic dashboard,
which it's amazing at. But can we really put it to the test
and make this basically real time multi user application,
but still on web fundamentals, still with progressive enhancement and
covering all our bases. Is that possible? Let's have a
look. So to build something like this, we have a couple of features
that we need to support. Firstly, you need to be able to create
and join a session. So you need to have some forms where we
can start a new session where we can join
one, give your username, et cetera. Well, naturally you need to cast
a vote or an effort, depending on how you call it in your team
saying, I think this story is worth five
points or eight or whatever. Then when everybody voted,
you want to toggle the visibility so everybody can view what everybody voted
and at the end the admin can clear it around and restart,
put the visibility back to hidden and you do the process again.
So quite a simple app, basically four features,
but can be quite complex to build in the end, if youre going to build
that for the web. So let's have a look at how we can use web
fundamentals for this.
Let's get the party started. So the lineup or the
tech stack for this is well naturally remix. That's the framework of choice that
we're going to look at today. Then I needed to persist some data, right,
youre want to maybe store the session state,
maybe some users. I use superbase for that,
which is basically if you know, Firebase, I think they market themselves
as the firebase alternative. Do it
what you will, but at least I like it for these type of applications.
Short demo, small applications. Finally, we need to
add some styling, make the demo look a bit nicer.
For instance, something like tailwind can help you quickly style
your pages. So that's what I used. I tried to remove
as much of this out of the code examples as I could and simplify
the code examples. But just so you know,
this is the entire text deck. So how does that visually look
if we design it? Well, basically we have this index
page where we can create a new session by giving
our name, or we can join an existing session
where we pass it, the session id that we want to join and
our name there. So basically two forms,
then we have a dynamic session page. So for instance,
session whatever id we put in
there. And this already becomes quite more complex,
right. We need to show some data, we need to add some interactivity
and so on and so on. So these two pages will be the base of
our entire application. And let's see how we can build that.
So if youre ever worked with something like next JS, I think
it's now also in new react router. This will be familiar,
but basically what we use is file based routing where we
have in remix an app folder, where we have a routes
folder. And when I put an index TSX file in there was long
as I export some JSX, I can
go to index HTML and see that page.
Similarly, if we make a folder called session with a file
in there, it will be session whatever file you
put in there. So you notice that I have this little dollar sign and that
is basically remix way of saying, okay, this is a dynamic part
of the URL, this is the session id. So whatever
somebody puts in there, match on that and load this file
and there we can handle our logic. Finally, we have this root TSX,
which is basically the wrapper around the entire application remix,
or rather react router nowadays because they moved it over can do really
cool things with its routing, with nested subroute, with outlets.
Really amazing. You can find all of that in the basic readme of
remix. So please head over there, but be sure to check it out.
So let's dive a bit deeper. The create or join session page as
I call it here. So we have those two forms basically do
similar things, but they both need to be handled. Okay, so how
did we in the past handle a form on the web?
Well, we did something like this. We said well we
have a form with a label and input and a button that submits.
So what you see here is that I actually import something from
remix called form. And what's good to know is that underwater this
will just render a native HTML form
element in your page. So that's great. And we'll
get to see why we actually use this instead of just the native
form element in a bit. And as you notice here,
I don't have any prevent default, no event
listeners, I'm actually just going to say method is post submit
this thing. And in the past this was not ideal because these frameworks,
especially these front end frameworks, when you posted it, well it
had nothing to post to, right? If you just had a create react
app and youre post, there's no server running there, there's nothing
that can handle my post request. So I had to have
an on submit event on the form, prevent the default, then get
the data, get it from the state and add all this logic to
my application which by the way just works when youre have client side Javascript,
which is not ideal because the web is really good at submitting
forms. So let's just submit it. So where do we then handle that?
Well, in that same file. And note that these are simplified code
examples. So I've hidden the JSX here that we just saw.
In the same file I export something which is called an action and
this is basically a server side function. And this server side function
needs to be named action, like exactly action
and be exported. So remix will pick it up. And what
it does is whenever you post something from the front end and
do an actual post request, this function on the server will
be ran. So as you can see here, I dave
a request that's coming in and in that request
there's just form data. Well we get the form data,
we get the username and this is usually when I show this where
older developers say hey oh, that's how I used to do
it. Exactly. And it's still perfectly fine. So here
we then say, okay, I will create a new session id. I use a nice
package called human readable ids because it's a bit nicer
to read those than these gigantic
randomly generated ones. But then I call
something called superbase client. And what's just important for you to know
is that superbase client is just an SDK by
superbase that allows you to talk
with your database. So here we say okay, go to sessions, insert a
new session with this session id, and then something cool happens.
So what we do is say, okay, we need to return something from this
function, always. So what we could return is a redirect
which we import from remix. And that does exactly what you think, it just
redirects the page to whatever you want. So in our case, that might
be nice to redirect to sessionnewsessionid,
but what the remix is really focused on is also your error handling,
which in the readme of remix there's a lot of information there.
But what I use, for instance here is say okay, well, if this superbase
client returns me an error, I don't want to redirect, I want to show what
went wrong. So how do I do that? Well, I just return an object
here to be used. So remix can handle this.
But how do I then actually get that object with the error data?
Well, I use something of remix called the use action data.
And this is a hook that whenever your
action is ran and it returns something, this will be updated
if you have clientside like javascript. So this is where that form package comes
in. So instead of just a regular, which will still work, by the way,
a regular HTML five form, when you submit it,
it does a full request to the back end, it's going to handle your logic,
you're going to return error, it's going to do a full rerender of the page
and you actually see your browser basically refresh the page.
But when you have client side javascript, it can do all of this
on the clientside, right? It can enhance the user experience. It doesn't need to fully
do a reload and be time consuming. No, it can just do it on
the clientside for you. And in that case this action data will also
be filled and the render method will run again and we
can display them. Do whatever you find logical in this case.
But this is a real core concept of how remix works,
which is great because I don't know a lot of frameworks that handle form so
well. So if you know regular old posts,
it's basically that, and underwater remix will enhance the
user experience for you. So that's great.
So progressively enhance with JavaScript.
And I will say that a lot during this
talk and I can already hear you saying yeah,
okay, but all my users do have JavaScript and the point
is not about the user not having JavaScript.
And I like to refer to this tweet from 2012
from Jake Archibald basically saying we don't have non JavaScript
users. No, all your users are non JavaScript users while they're
loading your javascript. That's the first example. So if youre
resources don't load or aren't loaded yet,
if your application doesn't work, what does that say for your user experience?
Right, and we shouldn't so heavily rely on
having this client side JavaScript. So this is while it's loading. But even
if it's loaded, I'm sorry, even if it's loaded,
you're still not but of the woods yet. So I gave this presentation
to a few colleagues and I was talking with one of my colleagues and he
said well Dave, I also built an app with remix
like two months ago, like oh cool, let me see. Then we visited
the page and he hadn't touched it in two months and the
page was just blank. Well, remixes. Of course
you can still do whatever you want, you can still introduce a lot of client
side JavaScript, but what I told him is like well maybe just
turn off your javascript for a second. And suddenly his entire application
worked again, because it just used the server side actions, it just
used the server side routes and used the web. And that's so powerful that
even if your clientside Javascript, which might be error prone,
even if that fouls, you still have hopefully a working application.
I mean you can always run into the issue of having the full white page,
sure, but at least if you put enough on the back
end instead of the front end, you can make your app a bit more
resilient. Okay,
cool. So we had that first form, that was basically it,
that's how you handle forms. And then of course we
have a second form. So I already told you that whenever you submit
and you have an action in that same file or in that same route,
rather the action will pick it up. But what if you have
two files, two forms, sorry, do you then have two
actions? Well no you don't.
So we need to use an alt trick that some
of youre might remember, which is just a hidden input. So for instance
in this hidden input we can say well the form type is
join session. And for the other one we say the form type
is create a session. And then what we can do is when this
information comes in on the action, we can say,
okay, well get that form type from the form data. And then,
well, I made a switch here saying, oh, take the form time,
create session, you should do this, this, and this. Join session, you should do this,
this, and this. So that's an easy trick how we
can basically reuse the same action but for different purposes on that
route, for different forms on that route. And that's it.
This is how simple you can make it.
Okay, so it can handle basic forms. It's really
nice. But of course we need way more if we want to create this real
time interactive web application. So let's have a look at
that dynamic page. Once you join or created a session
where you can actually run the application that looks a
bit like this. And there are a couple of parts here. So first we have
this top bar, and in this top bar we basically want to load some data
and show whether somebody has voted or not. If the
vote visibility is toggled, we might want to show the actual vote
that they did, but otherwise just voted, not voted.
Then we have the core of our interactivity for the user,
which is here. So note that this is the view of an admin
youre can see that by the show votes and the clear votes button
at the bottom, or rather toggles maybe that's
just shown for the actual admin. The rest just sees that grid
of choices. And then in the end we have this
little bit where we say copy invite because of course somebody starts a session
and then you want to share that with your team, maybe in a team's chat
and you want to send a link. So first let's have a look at that
so we can finish up the previous page we looked
at. So of course you can just
copy something from the URL. It's maybe not as nice as a user experience.
So what I did is I said, okay, I'm going to have this little components
which has a button called copy invite. And what does this button do?
Well, basically whatever your domain is on the index
page, it's going to pass a query parameter saying join
session id. Splendid Al 40 in this case.
So when you hit this button, if you are on a mobile device,
well there's something web standard which
is the native share API. So I'm going to check is
that available? Use that and you get
slack and teams and all those chat
tools so we can really leverage whatever phone they use.
If that's not supported. Well then let's have a look whether we have clientside
Javascript because maybe we can then put it
on the clipboard so somebody can paste it and otherwise
this can just be the entire URL that we see on the left and
somebody can manually copy that. Okay, so when somebody goes
back to that index page with the forms, we need to handle basically
this query param. So how do we do that? Well, we're going
to do some starts server side rendering and that's important. It's on the server
side for a better user experience.
So whenever somebody visits
this page with the search Param,
we can basically get it out of there using the use search params.
And why is this important? Because I understand that you
can add a use effect and basically do this manually.
See okay, what are the search parameters? The downside is the use
effect is clientside and what you get then is that it's
going to render this page. Then you're going to check whatever you need
to do and then you're going to maybe update the layout so you
get this flash of content, which is annoying.
We can already do this on the server. So this hook first
runs when this page is rendered on the server. And there we can see okay,
is there a join session id param or not?
Well if it is there,
if you have to join session, you might not want to show the
create a session form, right? Doesn't make
sense. Somebody's intent there is to join a session, not create one.
We'll hide it. Secondly, what we can do
is say in the join existing session youre might already set
the default value there for this input to be that
value. So the user of course doesn't have to type it in.
What we can also then do is say maybe I want to auto
focus on the name input there so the page loads, you will just
see the form and it will look a bit like this.
Yeah, so a bit smarter way of rendering but also enhancing the
user experience. Again, to for instance auto fouls on
this name input, you type your name, you hit enter, which by the
way will work because we use native form submits
and all the logic is executed to basically redirect
you to the page of successful.
Cool. So we talked a lot about posting
data and handling that in the back end and a bit of routing. But of
course a big part of your application is actually displaying data that's
probably stored in the database somewhere. So like this bar on top.
So let's have a look at how you do that.
Unsurprisingly, it looks a lot like that action that we looked at.
So instead of an action you have something called a loader.
And if youre worked with next JS, this is probably fairly
familiar to you because this is sort of like get surropsite
props, right? It's a function that whenever somebody fits a URL,
it's first going to go to the server, it's going to execute this function where
we basically get our data. So in our case
here in the example we get the current session.
If the session doesn't exist, maybe we redirect, we can handle this
however we want, but after that we're going to get everybody's vote
for this session and then return that
data. So how do we now access it with
the use loader data instead of use action data?
So this is the pattern that remix keeps on following.
So the first time it's going to render on the server, this loader data will
be filled with the votes and the session data.
You do render your HTML or JSX accordingly.
And then on the clientside, if you don't
have any use effects or client side Javascript
that needs to be executed, this is it.
Cool. So we can get the latest state from the server basically of the
session and display that. So we need to also
add some interactivity now. So at the start nobody has
voted, but we do wanted to do that. And this is usually
where we tend to reach for client side Javascript.
We see a bunch of buttons, we see
a grid of votes, and it's like oh okay, we'll need state and somebody's
active vote, and I need to keep everything in sync
and whatnot. But even worse, once we
have this clientside Javascript, we need an API to post this to.
Then that API needs to be hosted somewhere.
You might run into stuff with cores, you need
API keys, it gets way more complex, while all I want
to do is just send some data over.
So let's have a dive into that, into these interactive
bits, or rather these microforms as I like to call
them. So let's look at the voting first.
Right here we have this grid and
let's see how we can make this work without client side Javascript. And what's
good to remember is again, it's not about your user not having client side JavaScript,
it's about reducing the complexity of your app. First of all
by having way less client side Javascript that needs to mimic
browser behavior, have less error prone
logic because of that, and really get this solid base in there
and then enhance it.
After that we can have a look at the show votes toggle and the clear
votes toggle. Cool. So looking at that grid,
and I called it a grid on purpose because I didn't want to call it
a radio button group right out of the way. But isn't that what
it is? So isn't it basically here
a field set where we have a bunch of radio inputs
that have the Fibonacci sequence here where you can vote?
And why I'm saying this is because the radio buttons do exactly what
we wanted it to do. You can always just have one active
vote, and when you click a new one, the old one should
go back to not being checked and the new one should be.
So this works really well, it covers everything that we need. So let's just build
it like that then with CSS. And actually you could basically hide
the little radio button, make the nice square and have it light up.
That's all on the CSS part, which a lot of people are familiar with on
how to do that, but underwater it's just this cool.
So one drawback
of going to forms for this is whenever I hit
one of the radio buttons, nothing happens because
we still need to submit it. So I need to have a submit button at
the bottom and then I can post it without any clients or Javascript. But that's
not very nice for my user experience. That's not what we want. So let's have
a look at how we can do that. We can use something that's called
the use submit, and this is something by remix where you can
basically say okay, I want youre to submit this form now,
and I want to submit to the normal action that you
would otherwise. So here I add an on change handler
to this little form where I say when something
changes, just submit it to the back end or to the action rather.
And note that we don't prevent default because we wanted
the default, we just want to submit this thing. Cool. But now
I'm still left with this tiny button which says submit
at the bottom, which is not needed if you have client side JavaScript.
But how am I going to hide it or show it?
Because you basically don't have, for instance client side JavaScript to check
whether you have client side JavaScript and you don't want flickering of your UI.
So don't be scared, we're going to have a look at some CSS.
You can do this in a million ways and probably better ways than I have
it here but just to showcase you can do something like say
okay, I'm going to say set a data attribute on the
body saying there's no Javascript, and then whenever
there is clientside Javascript it's basically going to update the value to
true. So then what we can do in our CSS and we can create some
helper classes like no JavaScript show or no
JavaScript hide. And based on that we can
say well if that attribute is true or false, we're going to show or
hide anything that has this class name.
And I do some trick here with animations and why
do I do that? Well of course we want to give
JavaScript a second to load. So whether you want to hide certain
UI parts, you want to give that check
or basically the clientside said Javascript bundle some time to actually load. So in
this case I just gave it 500 milliseconds and after that
these things will come into effect. So it's a small little trick where
we now have some reusable CSS classes, which is nice to use for youre team
to show or hide specific content for both
use cases. So now we show
manual submit button for the non JavaScript UI using
the CSS. Cool. So these two
action buttons at the bottom. Well how
are those microforms? Well, let's do the
same thing as first we'll just create two forms
which have two inputs which are basically hidden and say
I want to toggle the effort or I want to clear the effort.
This is the only way you can have these buttons
in our forms to have these interactive bits without clients
or JavaScript because the only interactivity that you can actually have is posting
this to the back end. And what we do is
just have these two forms here and then again use
that same trick in that action we're going to check. Okay,
what is the form type? When it's toggle effort you might want to do something
in the database. And with clear effort it's the same and that's
it. I mean it's not much harder than having
an event listener on a button and then having to post to an API.
No, it's just a form that now natively submits a new
handle. Works perfectly fine with or without JavaScript.
Great, so let's Dave a look like every party,
you also Dave a bouncer in front of it saying can you show
me some id? Right, we need to see who
the person is that is actually casting a vote so they can just update
their own. But you also want to know who the
admin is so they can toggle the visibility.
So when I was quickly building this, I just had a query parameter with the
username. But of course you can fill in somebody else's
username and then basically cast a vote for them or become admin,
which is not great. I didn't want my
user to have to do a full sign up because now I just want to
do some scrum poker and who is Dave and why does he want my data
and I don't actually need it. A username is nice to show who is
who, but you can fill in whatever you want. And besides that I just need
some basic information like a unique id.
So what do we Dave on the web that is
accessible on the server where we have our mutation logic and
our data loading logic, and how can we make
it only known basically to you as a user and not
to anyone else? We can use server sessions,
which are really cool, which is nothing new.
Remix offers a couple of helper functions to
get you started. In essence, if you've never worked with it,
basically you can have this unique session
in your browser. You start your browser up, go to this page,
and for this session we can keep track of
you basically. So what we do there is we're
using to save some data for you.
I appreciate that these code examples become a bit tidy,
but just follow along because
this is a very simple part. Basically what I'm doing here is
I'm saying, okay, I have that cookie session and I'm going to set
for this session id that I'm joining. I'm going to set
my user id and my username. User id being a
unique id and a username whatever somebody inputted.
So when we handle the form for create session or
join session, we store that information.
So we can do now is when you're on that dynamic session page,
whenever you want to cast a new vote,
you want to say, okay, I think this
is worth five story points. You're not going
to send along who you are. Well, on the water it will,
but you are not. As a developer, you just say for the current
active session this user wanted to
vote the value of five. So here I can do session get
with that session id and I can basically get the data for you. So your
username, your user id. So this makes sure that I can
just store your vote. And you can never
store somebody else's vote because, well, it's not your session and
you don't even know their id.
Well, you don't know their id. If we make sure that you
don't because you can imagine if we have
these votes and we store these votes and for everybody, we're going to
return this data. These votes will contain everybody's
user id and youre don't want to expose that because it's not needed for everybody.
So what you can do, and that's a real added benefit of these server side
functions here in that loader we say, okay,
I'm just going to check whether I'm an admin and whatnot, but I'm also going
to filter out this votes array.
I'm just going to send back basically somebody's username and the
effort that they gave. So for instance, five or three, but I'm not going
to send back their user id because you don't need it
in the application, so don't show it. We do everything on the server
where it's safe and on the client is as dumb as we can keep it.
We can even make this more secure.
So basically we have this superbase and you can
call to that superbase app. And how
can I make this a bit more secure? Well,
I can really leverage that server side only
mutation part. So what I did is I said, okay,
all my policies in superbase, I'm going to block everything.
Doesn't matter which token, I'm going to block everything. Nothing gets
past this. But I'm also
going to create a server only token which youre can do in Superbase,
which is basically the super token that can bypass
these policies. So I'm going to get this server only token
and what I do is I put it in
my process env, which is a known pattern, I think to the most
of you, but basically saying, okay, this is whatever that secret key is.
And now this was, we just run it on
the server will never expose that key. If you want to
be sure, for every file that you want in remix,
you can say server ts as
a post fix to the file and it will make sure that it can just
run on the server. But it does a good job regardless.
And because we use this just on
the server, I can just call this and we're safe
in our security even more secure.
So it feels a bit slow, right? Because you can imagine
previously youre just hit a button, event listener post an app
and you'd update youre UI. But now we're
submitting a form post that goes to that action. That action
is going to talk to Superbase. Superbase is going to do an update in the
database. Then Superbase is going to say, hey,
it went well. And it's going to come back again to us. Then we're going
to say okay, in our UI we then update
or redirect or whatever you want to and then you see it.
So that is annoying. But it's even youre annoying when
you have basically that grid of options to
vote on. Because when I click that and I have to wait for this
entire round trip before I can get the feedback in the UI.
That's another nice user experience. And I promise you
that we were going to use web fundamentals and enhance them to create
a better user experience. So let's have a look at how we can make that
a bit better. We can use something that's already existing online,
which is called optimistic UI. And the gist of it is saying okay,
I'm very optimistic that my code works. Basically I'm
saying you hit submit, we know what you want to submit,
we're already going to update the UI was if it went successful,
then when the response comes back and it says it is successful,
perfect, we don't need to do anything anymore. Once it says that there's an
error, we need to put it back. This can be a bit cumbersome, but luckily
remix thought about this and added something
called a use transition. And what does a use transition do? Well,
basically it has a transition state and you
have this hook. For instance on your dynamic
session page you listen to the transition state. So whenever
any form on that page is submitting that
transition state updates from idle to submitting doesn't
do just that. So when we listen to it and we say okay,
it's submitting, we can basically access that form data
the same as we did it in the action. We can
already do that here client side. So what we can do
is get the data out of there, maybe add some little bit
of client side state to show the optimistic vote here
and clear it again once it's idling and then we can already update
the UI. So what we basically do is see that we
have on the 8th line we
have active user effort where we basically say use the optimistic vote or
the loader data vote and then use that in
the render logic. And I know I said no client side Javascript
state sure you can have client side state. If you want to enhance it,
it's perfectly fine. But first cover your basis, have everything working
and then see okay, how can I enhance this on the client and
you can do it like this. If my client's Javascript doesn't load or something
breaks, my normal flow will still work. It's a bit slower,
but it will still work.
So one thing I haven't talked about yet is going
real time. And you can imagine if you
first build your application fully real time and then
try to bring it back to one that works
with that client side Javascript. That's really difficult to do by the way,
which is called graceful degradation instead of progressive enhancement.
So how difficult is it now to go real
time with that solid base that we have? So how can I have this
Modern Ux? Because technically I don't need clients at
JavaScript. The user could refresh and get the latest version,
but that's not the nicest, right? There's an admin that's going to toggle the
view, it's going to reset around. So how can
we work with this? Naturally I need clients at Javascript to
have these real time updates, but let's have a look at how
that works. So first I created something which is called,
I call it a use superbase subscription. So what is a
subscription in Superbase? It's basically this little socket
connection to Superbase where you can subscribe on
any change that you want to. So what I
did here is that, okay, I'm going to listen for
any query that somebody passes to this custom hook and
then on, well whether it's a put or delete
post, a get whatever, whenever there's an update I want you to call the
past callback. So great.
In this callback I get the little record that got updated.
So let's say that you updated your vote to eight,
I will get your user which says I
updated this to eight,
please update your UI. So what I did naturally was say okay,
thank you and I'm going to push that through some client side state.
But when you have a lot of people and all
spamming the buttons, you have to sort of trust that it comes in at
the right order. Suddenly I was keeping track of basically
against state and basically a copy of whatever was in the database and I was
trying to keep it up to date and I ran into some issues and then
I thought well no, I already
have the logic to get the latest state out of the database,
basically refreshing my page. Can I just reuse that?
You can. So what do I do now? Instead of
pushing into started, I use the last hook that I want
to show you, which is called the use fetcher. And in
essence what a fetcher does is you can have it
rerun your loader function that you have on your file.
So our loader function give us the latest state. So when somebody visits the URL,
they're going to see the latest state. But then what we can do is call
this fetcher. And then in fetcher it will have a
key called data, which will then be filled or not.
So the first time this page renders fetcher data is
empty. So the loader data will
be used. But when we say, oh, we have
a callback and I'm going to fetcher load, well, my current path,
this fetcher is going to be filled with again the latest
version of the data. So now I'm basically just listening. Hey, there's an
update. Just rerun my logic and have the data there.
But with this simple or statement here, we can say which one
we want to use and that's it. That is the entire
layer of adding real time to this application.
And I'm not that surprised that it is this easy because
I first built this solid base and now I enhance that.
So then you go for a test run. Well, this is me going for a
test run with my team. So on the top right we have the
application and on the left I have my teams call. Well,
naturally, since there are a lot of developers in these meetings,
they're trying to submit the form with things like drop table and
try to see if I screwed up somewhere. Luckily I didn't.
But more importantly, suddenly I had all these people just randomly
selecting votes and tapping it. So really stress testing my system
and my poor free superbase subscription, having all those requests
going on, that was not the best.
So what I did is I throttle it and normally youre
would be like oh, why would you trottle it? You make your application slower.
But we do this in a bit of a smarter way. So we
have this optimistic UI part. So when you click
on for instance, eight, it updates immediately for
you that it takes a while in the back end,
sure. But for you it's instant. So you have this feeling
of an instant update whenever
somebody else pressed on a
vote of, for instance, one. If that takes 1 second before I execute
it, are you really going to notice, do you know exactly
the millisecond somebody pressed on it? So this is how I could just say,
okay, well let's maybe throttle this for my demo and for my free
superbase subscription.
So now me and my team can actually just use this.
And it's been serving us really well for it.
Great. So we looked at a lot,
right, all these little parts and that was the exact intent
of building this application. You have so many of these. We basically had four little
features, but look at how much complexity it even becomes
when you try to keep it simple. And what I want to show
here is that remix isn't just simple forms. And when you talk with
people about remix, they will most likely talk about forms
and having the dashboards and all those standard applications.
But you can see we fouls easily. Just create a real time application.
Not because it's all remix that offers that.
No, it offers this solid base which makes it easy for you to
add it on there, which is how I believe you should always build.
A big benefit was that we basically moved
all the state to the server where we could because
we have the latest state on the server. We don't have all this client side
logic that you need to keep in sync, keep up to date, which suddenly
becomes very complex. And when you dave complex client
side state youre going to introduce something called Redux, which needs a redux
saga, which is going to need, and you run into this gigantic system.
Well, all you had was basically a simple bit of data.
Databases are perfect at keeping the latest state. Just get
that and use these tools to do that and
use web fundamentals. So I said that quite a few times during this
talk and that's really what I want to get
across, that if you use these web fundamentals which are
proven technologies fully optimized for the browser that your
application actually going to run in, really use that,
it's really good at all these things. But then sure,
enhance for modern Ux. So basically do it in that order
instead of the other way around.
Finally, it's not about remix, the framework itself,
which is a weird statement after talking for 35 minutes
about a framework, but it's more the thought behind remix.
Right. It's basically pushing to use
the web was a platform more and that's going to benefit you because
if you pick up a framework like remix and another framework also relies
heavily on web fundamentals, you can really leverage
all your experience and your mental model of how you build it,
but then just learn what is slightly different in the API of that
new framework. So yeah, I'm really excited
to see that we finally are going to,
I feel like a web developer again, basically instead of a JavaScript
engineer, and to really embrace that beautiful platform that
we all know and love and want to build for.
And with that I wanted to say thank you. I hope
I inspired you to try remix
out or think about progressive enhancement or web fundamentals
in general in your application and see where you can
actually apply some of these techniques or really rethink the
way that you build your applications. These are my
socials, so please don't hesitate to reach
out to me. And if you have any questions,
please send me a message and
I will respond right away. And with that, I wanted to say thank
you for your time, and I'll see you next time.