0:03
so I'm going to be doing a session with
0:04
so I'm going to be doing a session with
0:04
so I'm going to be doing a session with mostly live coding today um with the
0:06
mostly live coding today um with the
0:06
mostly live coding today um with the goal of teaching how to work with forms
0:08
goal of teaching how to work with forms
0:08
goal of teaching how to work with forms and RC's in
0:10
and RC's in practice so first about me you saw that
0:13
practice so first about me you saw that
0:13
practice so first about me you saw that was a really nice intro intro there but
0:15
was a really nice intro intro there but
0:15
was a really nice intro intro there but I'm from Norway I work as a consultant
0:17
I'm from Norway I work as a consultant
0:17
I'm from Norway I work as a consultant at in meta and I work in AO and I'm
0:20
at in meta and I work in AO and I'm
0:20
at in meta and I work in AO and I'm mostly working with FB development and
0:22
mostly working with FB development and
0:22
mostly working with FB development and in my current project at my consultancy
0:24
in my current project at my consultancy
0:24
in my current project at my consultancy I am actively building with RC so I hope
0:27
I am actively building with RC so I hope
0:27
I am actively building with RC so I hope to share some of my experience here uh
0:28
to share some of my experience here uh
0:28
to share some of my experience here uh from that with you
0:31
from that with you so let's begin by looking at this
0:32
so let's begin by looking at this
0:32
so let's begin by looking at this typical single page application it's
0:34
typical single page application it's
0:34
typical single page application it's great you have your react query your
0:36
great you have your react query your
0:36
great you have your react query your react form and all is well but as we
0:39
react form and all is well but as we
0:39
react form and all is well but as we know client ads have their
0:41
know client ads have their
0:41
know client ads have their problems so they run purely with
0:44
problems so they run purely with
0:44
problems so they run purely with JavaScript and the entire page or theab
0:46
JavaScript and the entire page or theab
0:46
JavaScript and the entire page or theab application is constructed from
0:48
application is constructed from
0:48
application is constructed from JavaScript when the user opens the URL
0:51
JavaScript when the user opens the URL
0:51
JavaScript when the user opens the URL if you're working for uh from a slow
0:53
if you're working for uh from a slow
0:53
if you're working for uh from a slow device or slow connection it can take a
0:55
device or slow connection it can take a
0:55
device or slow connection it can take a really long time to download and execute
0:58
really long time to download and execute
0:58
really long time to download and execute and uh uh part download person and
1:00
and uh uh part download person and
1:00
and uh uh part download person and execute all this JavaScript to even load
1:02
execute all this JavaScript to even load
1:02
execute all this JavaScript to even load the page to you know fill out a simple
1:04
the page to you know fill out a simple
1:04
the page to you know fill out a simple form something like that and in addition
1:06
form something like that and in addition
1:06
form something like that and in addition to submit data to a database you would
1:08
to submit data to a database you would
1:08
to submit data to a database you would want to need a backend because you can't
1:11
want to need a backend because you can't
1:11
want to need a backend because you can't rely only on the client
1:15
validation uh and even with a framework
1:17
validation uh and even with a framework
1:17
validation uh and even with a framework like next yes you might still have
1:19
like next yes you might still have
1:19
like next yes you might still have issues because even though you fix your
1:22
issues because even though you fix your
1:22
issues because even though you fix your problem uh of blank screens by randoming
1:24
problem uh of blank screens by randoming
1:24
problem uh of blank screens by randoming the pages you now have an even bigger
1:26
the pages you now have an even bigger
1:26
the pages you now have an even bigger dependency waterfall of uh downloading
1:29
dependency waterfall of uh downloading
1:29
dependency waterfall of uh downloading parsing executing the job JavaScript
1:30
parsing executing the job JavaScript
1:30
parsing executing the job JavaScript then hyding the hydrating the entire
1:33
then hyding the hydrating the entire
1:33
then hyding the hydrating the entire page before anything really
1:36
page before anything really
1:36
page before anything really works and let's not forget the struggles
1:38
works and let's not forget the struggles
1:38
works and let's not forget the struggles of working with form in the nextjs pages
1:40
of working with form in the nextjs pages
1:40
of working with form in the nextjs pages router so back then uh you had to
1:43
router so back then uh you had to
1:43
router so back then uh you had to manually create your own API endpoints
1:45
manually create your own API endpoints
1:45
manually create your own API endpoints every time you wanted to safely submit a
1:47
every time you wanted to safely submit a
1:47
every time you wanted to safely submit a form to the server you would want to use
1:49
form to the server you would want to use
1:50
form to the server you would want to use a library like trpc to ensure type
1:52
a library like trpc to ensure type
1:52
a library like trpc to ensure type safety you might have to write a bunch
1:55
safety you might have to write a bunch
1:55
safety you might have to write a bunch of excess messy code especially to
1:57
of excess messy code especially to
1:57
of excess messy code especially to handle errors and loading States so
2:00
handle errors and loading States so
2:00
handle errors and loading States so overall it was not a good developer
2:03
overall it was not a good developer
2:03
overall it was not a good developer experience so with the react server
2:05
experience so with the react server
2:05
experience so with the react server components uh which was announced as RC
2:08
components uh which was announced as RC
2:08
components uh which was announced as RC at react conf in may we now have server
2:10
at react conf in may we now have server
2:10
at react conf in may we now have server components react server components will
2:12
components react server components will
2:12
components react server components will run only on the server so therefore we
2:15
run only on the server so therefore we
2:15
run only on the server so therefore we can fetch data asynchronously inside
2:17
can fetch data asynchronously inside
2:17
can fetch data asynchronously inside components and access all our backend
2:20
components and access all our backend
2:20
components and access all our backend resources which will reduce the bundle
2:22
resources which will reduce the bundle
2:22
resources which will reduce the bundle size by minimizing the JavaScript sent
2:24
size by minimizing the JavaScript sent
2:24
size by minimizing the JavaScript sent to the client and then let us build
2:25
to the client and then let us build
2:25
to the client and then let us build performant apps with enjoyable
2:27
performant apps with enjoyable
2:27
performant apps with enjoyable developers experience
2:31
so what we want to do today is use react
2:34
so what we want to do today is use react
2:34
so what we want to do today is use react server components to write performant
2:36
server components to write performant
2:36
server components to write performant userfriendly forms without a lot of
2:37
userfriendly forms without a lot of
2:37
userfriendly forms without a lot of front and complexity we're going to need
2:40
front and complexity we're going to need
2:40
front and complexity we're going to need a framework uh to use RC's inside and
2:43
a framework uh to use RC's inside and
2:43
a framework uh to use RC's inside and nextjs with the app rouder is our pick
2:45
nextjs with the app rouder is our pick
2:46
nextjs with the app rouder is our pick here then we will be needing multiple
2:48
here then we will be needing multiple
2:48
here then we will be needing multiple other react 19 features that are already
2:50
other react 19 features that are already
2:50
other react 19 features that are already available in the app router which are
2:52
available in the app router which are
2:52
available in the app router which are server actions the form component use
2:55
server actions the form component use
2:55
server actions the form component use action State use form status and use
2:57
action State use form status and use
2:57
action State use form status and use optimistic
3:00
so server actions are defined with use
3:02
so server actions are defined with use
3:02
so server actions are defined with use server and tells the framework like
3:04
server and tells the framework like
3:04
server and tells the framework like nextjs to generate a post endpoint to a
3:07
nextjs to generate a post endpoint to a
3:07
nextjs to generate a post endpoint to a function that allows us to call it from
3:09
function that allows us to call it from
3:09
function that allows us to call it from any component for example from a client
3:12
any component for example from a client
3:12
any component for example from a client component it simplifies the
3:13
component it simplifies the
3:13
component it simplifies the communication across the server boundary
3:15
communication across the server boundary
3:15
communication across the server boundary while providing type safety with
3:19
while providing type safety with
3:19
while providing type safety with RPC the form component is reacts uh
3:22
RPC the form component is reacts uh
3:22
RPC the form component is reacts uh extension of the Native form component
3:25
extension of the Native form component
3:25
extension of the Native form component which now Builds on top of its existing
3:27
which now Builds on top of its existing
3:27
which now Builds on top of its existing methods the extension will let you
3:29
methods the extension will let you
3:29
methods the extension will let you create interactive controls um for
3:32
create interactive controls um for
3:32
create interactive controls um for submitting information for example by
3:34
submitting information for example by
3:34
submitting information for example by letting the action property now also
3:36
letting the action property now also
3:36
letting the action property now also call a function typically it could be a
3:39
call a function typically it could be a
3:39
call a function typically it could be a server action so the function you pass
3:42
server action so the function you pass
3:42
server action so the function you pass will automatically be wrapped in
3:43
will automatically be wrapped in
3:43
will automatically be wrapped in transition contain a hidden form data
3:45
transition contain a hidden form data
3:45
transition contain a hidden form data argument with the values of the form and
3:48
argument with the values of the form and
3:48
argument with the values of the form and in the case of a server action be called
3:50
in the case of a server action be called
3:50
in the case of a server action be called as a HTP
3:53
as a HTP post the Ed form status Hook is a hook
3:56
post the Ed form status Hook is a hook
3:56
post the Ed form status Hook is a hook that provides information about the last
3:57
that provides information about the last
3:57
that provides information about the last form submission it can be used in inside
3:59
form submission it can be used in inside
4:00
form submission it can be used in inside a form uh
4:01
a form uh component um in a component inside a
4:04
component um in a component inside a
4:04
component um in a component inside a form and it can be used for example to
4:06
form and it can be used for example to
4:06
form and it can be used for example to display disable a button or display
4:09
display disable a button or display
4:09
display disable a button or display what's currently being
4:10
what's currently being
4:10
what's currently being submitted this hook enables progress
4:12
submitted this hook enables progress
4:12
submitted this hook enables progress enhancement because if the JavaScript
4:15
enhancement because if the JavaScript
4:15
enhancement because if the JavaScript has not hydrated the component it will
4:17
has not hydrated the component it will
4:17
has not hydrated the component it will still work it just won't display any uh
4:19
still work it just won't display any uh
4:19
still work it just won't display any uh pending feedback as we see in the the GI
4:23
pending feedback as we see in the the GI
4:23
pending feedback as we see in the the GI here use action state is another Hook
4:26
here use action state is another Hook
4:26
here use action state is another Hook from react 19 that allows you to update
4:28
from react 19 that allows you to update
4:28
from react 19 that allows you to update State based on the result of an action
4:31
State based on the result of an action
4:31
State based on the result of an action it also supports Progressive enhancement
4:33
it also supports Progressive enhancement
4:33
it also supports Progressive enhancement by allowing the server's response to be
4:35
by allowing the server's response to be
4:35
by allowing the server's response to be shown without JavaScript before
4:37
shown without JavaScript before
4:37
shown without JavaScript before hydration has completed this hook can be
4:39
hydration has completed this hook can be
4:39
hydration has completed this hook can be used for example to display air messages
4:41
used for example to display air messages
4:41
used for example to display air messages or other information that is based on
4:43
or other information that is based on
4:43
or other information that is based on the return value of the
4:46
the return value of the
4:46
the return value of the action and the final Hook is use
4:48
action and the final Hook is use
4:48
action and the final Hook is use optimistic which lets you optimistically
4:50
optimistic which lets you optimistically
4:50
optimistic which lets you optimistically update UI while a background operation
4:53
update UI while a background operation
4:53
update UI while a background operation completes it lets you keep the UI Snappy
4:55
completes it lets you keep the UI Snappy
4:55
completes it lets you keep the UI Snappy by providing instant feedback to
4:58
by providing instant feedback to
4:58
by providing instant feedback to interactions and you can use it with
5:00
interactions and you can use it with
5:00
interactions and you can use it with server actions and form submissions but
5:02
server actions and form submissions but
5:02
server actions and form submissions but it can also be used with other
5:04
it can also be used with other
5:04
it can also be used with other potentially slow operations such as
5:05
potentially slow operations such as
5:05
potentially slow operations such as filtering based on Route
5:07
filtering based on Route
5:07
filtering based on Route progams and it stands out because of its
5:10
progams and it stands out because of its
5:10
progams and it stands out because of its ability to seamlessly merge the client
5:12
ability to seamlessly merge the client
5:12
ability to seamlessly merge the client and the service state as the server
5:13
and the service state as the server
5:13
and the service state as the server finishes its
5:16
update okay so with that in mind let's
5:19
update okay so with that in mind let's
5:19
update okay so with that in mind let's move on to the demo I'm going to be
5:21
move on to the demo I'm going to be
5:21
move on to the demo I'm going to be coding a simplified version of something
5:23
coding a simplified version of something
5:23
coding a simplified version of something that I've made for my current
5:25
that I've made for my current
5:25
that I've made for my current consultancy project where we use
5:27
consultancy project where we use
5:27
consultancy project where we use RC so let me just jump over to uh my
5:31
RC so let me just jump over to uh my
5:31
RC so let me just jump over to uh my code
5:32
code here ah I need to reopen something here
5:35
here ah I need to reopen something here
5:35
here ah I need to reopen something here because it closed when I reset my um
5:38
because it closed when I reset my um
5:38
because it closed when I reset my um hold on one second
5:40
hold on one second here and we're here
5:44
here and we're here and we're going to go to Local Host
6:01
okay so I'm here in the nextjs app
6:05
okay so I'm here in the nextjs app
6:05
okay so I'm here in the nextjs app router and I'm using Prisma as my orm
6:08
router and I'm using Prisma as my orm
6:08
router and I'm using Prisma as my orm and I have a local database and I have
6:10
and I have a local database and I have
6:10
and I have a local database and I have Tailwind for
6:11
Tailwind for CSS so since we're in the app rou
6:13
CSS so since we're in the app rou
6:13
CSS so since we're in the app rou everything is a server component by
6:15
everything is a server component by
6:15
everything is a server component by default and uh this is all server
6:17
default and uh this is all server
6:17
default and uh this is all server components here for this message
6:20
components here for this message
6:20
components here for this message box so the message message box component
6:23
box so the message message box component
6:23
box so the message message box component is a server component it can be async
6:26
is a server component it can be async
6:26
is a server component it can be async and it can
6:27
and it can asly uh fetch message from our database
6:31
asly uh fetch message from our database
6:31
asly uh fetch message from our database using
6:33
Prisma and then it's um doing some nice
6:36
Prisma and then it's um doing some nice
6:36
Prisma and then it's um doing some nice styling and then mapping each message to
6:39
styling and then mapping each message to
6:39
styling and then mapping each message to individual message display
6:41
individual message display
6:41
individual message display components and this is also just uh
6:43
components and this is also just uh
6:43
components and this is also just uh styling based on whether the user is the
6:45
styling based on whether the user is the
6:45
styling based on whether the user is the one who has written the message or not
6:48
one who has written the message or not
6:48
one who has written the message or not and this is also just the server
6:50
and this is also just the server
6:50
and this is also just the server component and finally the message input
6:54
component and finally the message input
6:54
component and finally the message input uh another server component which is not
6:56
uh another server component which is not
6:57
uh another server component which is not really doing anything right now I can
6:59
really doing anything right now I can
6:59
really doing anything right now I can try out nothing's happening here it's
7:02
try out nothing's happening here it's
7:02
try out nothing's happening here it's just an
7:04
just an input so um what we want to do here is
7:07
input so um what we want to do here is
7:07
input so um what we want to do here is enhance this message box with react
7:09
enhance this message box with react
7:09
enhance this message box with react server components and react 19 where the
7:12
server components and react 19 where the
7:12
server components and react 19 where the goal will be to make this interactive
7:14
goal will be to make this interactive
7:14
goal will be to make this interactive while minimizing the js on the client
7:16
while minimizing the js on the client
7:16
while minimizing the js on the client and reducing the fronting
7:23
complexity so let's begin by making this
7:25
complexity so let's begin by making this
7:25
complexity so let's begin by making this form
7:27
form work so we're going to use react
7:29
work so we're going to use react
7:29
work so we're going to use react extension of the form component to bind
7:31
extension of the form component to bind
7:31
extension of the form component to bind this action property to a function we're
7:34
this action property to a function we're
7:34
this action property to a function we're going to call it submit
7:37
going to call it submit
7:37
going to call it submit message and it's going to be a server
7:39
message and it's going to be a server
7:39
message and it's going to be a server action so I'm going to make it inside my
7:41
action so I'm going to make it inside my
7:41
action so I'm going to make it inside my actions uh lip dat access layer
7:44
actions uh lip dat access layer
7:44
actions uh lip dat access layer here and we're going to use a server
7:47
here and we're going to use a server
7:47
here and we're going to use a server action here so we're going to say use
7:48
action here so we're going to say use
7:48
action here so we're going to say use server which means that the content of
7:51
server which means that the content of
7:51
server which means that the content of this file will uh the functions in this
7:53
this file will uh the functions in this
7:53
this file will uh the functions in this file will have a hidden post endpoint
7:55
file will have a hidden post endpoint
7:55
file will have a hidden post endpoint generated and we can call them from
7:57
generated and we can call them from
7:57
generated and we can call them from anywhere
7:59
anywhere and we're going to export an Asing
8:02
and we're going to export an Asing
8:02
and we're going to export an Asing function called submit message which
8:05
function called submit message which
8:05
function called submit message which takes in a form data uh argument of type
8:08
takes in a form data uh argument of type
8:08
takes in a form data uh argument of type form data and what this means is that
8:11
form data and what this means is that
8:11
form data and what this means is that each field in this form will be
8:13
each field in this form will be
8:13
each field in this form will be submitted with its value inside the form
8:15
submitted with its value inside the form
8:15
submitted with its value inside the form data object on
8:18
data object on submission and we can use this to um
8:21
submission and we can use this to um
8:21
submission and we can use this to um insert into our database with Prisma
8:24
insert into our database with Prisma
8:24
insert into our database with Prisma going to create a message where the data
8:26
going to create a message where the data
8:26
going to create a message where the data will
8:27
will be the content will be uh from the form
8:32
be the content will be uh from the form
8:32
be the content will be uh from the form data and we also need a user ID
8:36
data and we also need a user ID
8:36
data and we also need a user ID here uh sorry created by
8:39
here uh sorry created by
8:39
here uh sorry created by ID and I'm just going to close this up
8:43
ID and I'm just going to close this up
8:43
ID and I'm just going to close this up so somehow we need to pass an additional
8:45
so somehow we need to pass an additional
8:45
so somehow we need to pass an additional argument to our uh function and you can
8:49
argument to our uh function and you can
8:49
argument to our uh function and you can do this in a couple ways you can use a
8:51
do this in a couple ways you can use a
8:51
do this in a couple ways you can use a bind or just pass it inside the formul
8:53
bind or just pass it inside the formul
8:53
bind or just pass it inside the formul down so I'm going to do a hidden
8:57
down so I'm going to do a hidden
8:57
down so I'm going to do a hidden input um to pass the user ID inside the
9:00
input um to pass the user ID inside the
9:00
input um to pass the user ID inside the form data object and I'll import the
9:02
form data object and I'll import the
9:02
form data object and I'll import the function and remove this console
9:04
function and remove this console
9:04
function and remove this console log and it's worth noting that in the
9:08
log and it's worth noting that in the
9:08
log and it's worth noting that in the real world you probably don't want to
9:09
real world you probably don't want to
9:09
real world you probably don't want to pass your user ID uh from the client
9:12
pass your user ID uh from the client
9:12
pass your user ID uh from the client like this but this is just an example uh
9:13
like this but this is just an example uh
9:13
like this but this is just an example uh to show how you can pass additional
9:16
to show how you can pass additional
9:16
to show how you can pass additional arguments so let's try it out just like
9:18
arguments so let's try it out just like
9:18
arguments so let's try it out just like that I'm going to say hey and manually
9:22
that I'm going to say hey and manually
9:22
that I'm going to say hey and manually refresh the page and it's been
9:24
refresh the page and it's been
9:24
refresh the page and it's been submitted so it's just like that
9:26
submitted so it's just like that
9:26
submitted so it's just like that manipulated my database but I don't want
9:29
manipulated my database but I don't want
9:29
manipulated my database but I don't want to refresh the page manually of course
9:32
to refresh the page manually of course
9:32
to refresh the page manually of course so I'm going to use the next year's API
9:34
so I'm going to use the next year's API
9:34
so I'm going to use the next year's API revalidate path with the root path which
9:38
revalidate path with the root path which
9:38
revalidate path with the root path which means that I'm telling next yours to
9:39
means that I'm telling next yours to
9:39
means that I'm telling next yours to purch the server component cache and
9:41
purch the server component cache and
9:41
purch the server component cache and regenerate uh whatever is on this path
9:45
regenerate uh whatever is on this path
9:45
regenerate uh whatever is on this path so now I can say hi and it's been
9:47
so now I can say hi and it's been
9:47
so now I can say hi and it's been submitted without a hard refresh
9:51
submitted without a hard refresh
9:51
submitted without a hard refresh there now when I submit my message I'm
9:55
there now when I submit my message I'm
9:55
there now when I submit my message I'm still um in this scroll position where I
9:57
still um in this scroll position where I
9:57
still um in this scroll position where I don't see the new message so it would be
10:00
don't see the new message so it would be
10:00
don't see the new message so it would be nice if I can make it interactive by
10:01
nice if I can make it interactive by
10:01
nice if I can make it interactive by automatically scrolling to the bottom
10:03
automatically scrolling to the bottom
10:03
automatically scrolling to the bottom when there is a new
10:05
when there is a new message so I'm going to head over to the
10:07
message so I'm going to head over to the
10:07
message so I'm going to head over to the message box
10:08
message box component and I'm just going to change
10:11
component and I'm just going to change
10:11
component and I'm just going to change this div into an automatic
10:15
scroller and this component uh is a
10:18
scroller and this component uh is a
10:18
scroller and this component uh is a client component because it's using an
10:20
client component because it's using an
10:20
client component because it's using an effect and a mutation Observer to uh
10:23
effect and a mutation Observer to uh
10:23
effect and a mutation Observer to uh listen for a new child in the container
10:27
listen for a new child in the container
10:27
listen for a new child in the container and scroll to the bottom and this this
10:29
and scroll to the bottom and this this
10:29
and scroll to the bottom and this this requires JavaScript obviously um so it's
10:32
requires JavaScript obviously um so it's
10:32
requires JavaScript obviously um so it's a client component but since I'm
10:34
a client component but since I'm
10:34
a client component but since I'm wrapping it like this around server
10:36
wrapping it like this around server
10:36
wrapping it like this around server content using the children property I do
10:39
content using the children property I do
10:39
content using the children property I do not convert the content uh into client
10:42
not convert the content uh into client
10:42
not convert the content uh into client as
10:43
as well and we can uh prove that by looking
10:46
well and we can uh prove that by looking
10:46
well and we can uh prove that by looking inside the react Dev
10:48
inside the react Dev
10:48
inside the react Dev tools and see that there is an automatic
10:52
tools and see that there is an automatic
10:52
tools and see that there is an automatic scroller in the component Tre but there
10:54
scroller in the component Tre but there
10:54
scroller in the component Tre but there is no message display because only the
10:56
is no message display because only the
10:56
is no message display because only the automatic scroller has been shipped to
10:58
automatic scroller has been shipped to
10:58
automatic scroller has been shipped to the client as a component
10:59
the client as a component
10:59
the client as a component and has
11:02
and has JavaScript and let's see what it looks
11:04
JavaScript and let's see what it looks
11:04
JavaScript and let's see what it looks like now when we add a new message can
11:07
like now when we add a new message can
11:07
like now when we add a new message can say hi and it's now scrolling to the
11:09
say hi and it's now scrolling to the
11:09
say hi and it's now scrolling to the bottom uh with this interactive uh
11:12
bottom uh with this interactive uh
11:12
bottom uh with this interactive uh scroller
11:15
here so the next thing we should do is
11:18
here so the next thing we should do is
11:18
here so the next thing we should do is validate our data because form data it's
11:20
validate our data because form data it's
11:20
validate our data because form data it's from the client it's uh we doesn't we
11:22
from the client it's uh we doesn't we
11:22
from the client it's uh we doesn't we don't really know anything about
11:24
don't really know anything about
11:24
don't really know anything about it so we're going to get a result from a
11:28
it so we're going to get a result from a
11:29
it so we're going to get a result from a uh from a message schema which is a
11:31
uh from a message schema which is a
11:31
uh from a message schema which is a schema defined with sad which will at
11:34
schema defined with sad which will at
11:34
schema defined with sad which will at runtime validate or um validate whatever
11:38
runtime validate or um validate whatever
11:38
runtime validate or um validate whatever it's being U gets passed in to make sure
11:40
it's being U gets passed in to make sure
11:40
it's being U gets passed in to make sure that the content is at least one
11:42
that the content is at least one
11:42
that the content is at least one character and that the created by ID is
11:46
character and that the created by ID is
11:46
character and that the created by ID is a uh um unique
11:49
a uh um unique ID so we're going to safely parse um
11:54
ID so we're going to safely parse um
11:54
ID so we're going to safely parse um this object here that we were already
11:56
this object here that we were already
11:56
this object here that we were already using
12:01
and use that to um mutate
12:06
that to um mutate our and um we don't need to type these
12:10
our and um we don't need to type these
12:10
our and um we don't need to type these as strings because we're going to make
12:11
as strings because we're going to make
12:12
as strings because we're going to make sure that they turn into Strings when
12:13
sure that they turn into Strings when
12:13
sure that they turn into Strings when we're done with this
12:14
we're done with this
12:14
we're done with this validation and then we need to handle
12:17
validation and then we need to handle
12:17
validation and then we need to handle the case where this failed so if the
12:19
the case where this failed so if the
12:19
the case where this failed so if the result is not a success we can throw an
12:21
result is not a success we can throw an
12:21
result is not a success we can throw an error and say um invalid message data
12:24
error and say um invalid message data
12:24
error and say um invalid message data something like
12:26
something like that so um now if I comment out my
12:30
that so um now if I comment out my
12:30
that so um now if I comment out my client side valid validation and try to
12:32
client side valid validation and try to
12:32
client side valid validation and try to submit in a message invalid message I
12:35
submit in a message invalid message I
12:35
submit in a message invalid message I will get an error here because it didn't
12:36
will get an error here because it didn't
12:36
will get an error here because it didn't pass the
12:38
pass the validation and you can do whatever you
12:40
validation and you can do whatever you
12:40
validation and you can do whatever you want with your errors but uh a way to do
12:43
want with your errors but uh a way to do
12:43
want with your errors but uh a way to do it is by using an error
12:45
it is by using an error
12:45
it is by using an error boundary so I'm going to make an error
12:48
boundary so I'm going to make an error
12:48
boundary so I'm going to make an error boundary around this message
12:51
boundary around this message
12:51
boundary around this message input um and see how it looks now so if
12:56
input um and see how it looks now so if
12:56
input um and see how it looks now so if it's invalid the airror boundary will
12:58
it's invalid the airror boundary will
12:58
it's invalid the airror boundary will catch my error and U make sure that the
13:01
catch my error and U make sure that the
13:01
catch my error and U make sure that the whole app doesn't
13:03
whole app doesn't break uh so let me just put back this
13:05
break uh so let me just put back this
13:05
break uh so let me just put back this client side
13:07
client side validation and get back to the submit
13:10
validation and get back to the submit
13:10
validation and get back to the submit message because maybe I don't want to
13:13
message because maybe I don't want to
13:13
message because maybe I don't want to throw an error it's just a validation
13:15
throw an error it's just a validation
13:15
throw an error it's just a validation error maybe I would rather return
13:17
error maybe I would rather return
13:17
error maybe I would rather return something so what I will do is I will
13:20
something so what I will do is I will
13:20
something so what I will do is I will return a Suess
13:22
return a Suess false and I'm going to return a
13:24
false and I'm going to return a
13:24
false and I'm going to return a timestamp and we're going to use Slater
13:26
timestamp and we're going to use Slater
13:26
timestamp and we're going to use Slater I'm just going to create it now
13:28
I'm just going to create it now
13:28
I'm just going to create it now timestamp
13:30
timestamp H that's okay just like
13:33
that and I also need to return an error
13:37
that and I also need to return an error
13:37
that and I also need to return an error we can just say again invalid message
13:41
we can just say again invalid message
13:41
we can just say again invalid message data something like
13:44
that and then um maybe you want to do
13:47
that and then um maybe you want to do
13:47
that and then um maybe you want to do something else in on the server here
13:49
something else in on the server here
13:49
something else in on the server here maybe check that user exists could be
13:51
maybe check that user exists could be
13:51
maybe check that user exists could be anything in my case I'm going to limit
13:54
anything in my case I'm going to limit
13:54
anything in my case I'm going to limit the amount of messages the user can
13:56
the amount of messages the user can
13:56
the amount of messages the user can send so if uh actually we're going to
14:00
send so if uh actually we're going to
14:01
send so if uh actually we're going to get messages for a
14:03
get messages for a user and say await get
14:07
user and say await get
14:07
user and say await get messages for the user uh created by ID
14:10
messages for the user uh created by ID
14:10
messages for the user uh created by ID here and if it's bigger or if there's
14:13
here and if it's bigger or if there's
14:13
here and if it's bigger or if there's more messages than let's say five we can
14:16
more messages than let's say five we can
14:16
more messages than let's say five we can say user has to reach the maximum number
14:17
say user has to reach the maximum number
14:17
say user has to reach the maximum number of messages success fs and return also
14:20
of messages success fs and return also
14:20
of messages success fs and return also the time
14:21
the time stamp and if all as well we can insert
14:24
stamp and if all as well we can insert
14:24
stamp and if all as well we can insert into the database Ral dat the path and
14:26
into the database Ral dat the path and
14:26
into the database Ral dat the path and then finally return success true
14:30
then finally return success true
14:30
then finally return success true and if for some reason something goes
14:31
and if for some reason something goes
14:32
and if for some reason something goes wrong in this um
14:34
wrong in this um Prisma uh query here I can just let my
14:37
Prisma uh query here I can just let my
14:37
Prisma uh query here I can just let my air B boundary handle that
14:40
air B boundary handle that
14:40
air B boundary handle that problem so I have a lot of uh server
14:43
problem so I have a lot of uh server
14:43
problem so I have a lot of uh server side logic now I need to return this to
14:46
side logic now I need to return this to
14:46
side logic now I need to return this to the user
14:48
the user somehow so I'm going to use one of the
14:51
somehow so I'm going to use one of the
14:51
somehow so I'm going to use one of the new react 19 hooks called use action
14:54
new react 19 hooks called use action
14:55
new react 19 hooks called use action State and it will return first let's
14:58
State and it will return first let's
14:58
State and it will return first let's make this
15:00
make this uh it will take in a function to call on
15:03
uh it will take in a function to call on
15:03
uh it will take in a function to call on um Trigger or when it when the hook is
15:07
um Trigger or when it when the hook is
15:07
um Trigger or when it when the hook is being called and an initial State and
15:11
being called and an initial State and
15:11
being called and an initial State and the initial State can just be success
15:14
the initial State can just be success
15:14
the initial State can just be success false and it will
15:17
false and it will return uh a generated component state
15:20
return uh a generated component state
15:20
return uh a generated component state which is equal to First the initial
15:22
which is equal to First the initial
15:22
which is equal to First the initial State and then after that the last
15:24
State and then after that the last
15:24
State and then after that the last return value of the action that use
15:26
return value of the action that use
15:26
return value of the action that use action status
15:27
action status wrapping and it also returns returns a
15:31
wrapping and it also returns returns a
15:31
wrapping and it also returns returns a um a WRA action to calls which is going
15:33
um a WRA action to calls which is going
15:33
um a WRA action to calls which is going to call be called submit message action
15:35
to call be called submit message action
15:35
to call be called submit message action by convention
15:37
by convention here and I can use this to replace on my
15:40
here and I can use this to replace on my
15:40
here and I can use this to replace on my form action property and I can use the
15:43
form action property and I can use the
15:43
form action property and I can use the state to display an error message
15:49
here should be erir excuse me this
15:51
here should be erir excuse me this
15:51
here should be erir excuse me this should be erir over
15:53
should be erir over here like that now I'm getting the error
15:56
here like that now I'm getting the error
15:56
here like that now I'm getting the error from the from the action
15:59
from the from the action
15:59
from the from the action and there's a couple things I need to
16:01
and there's a couple things I need to
16:01
and there's a couple things I need to fix now first use action state is a hook
16:04
fix now first use action state is a hook
16:04
fix now first use action state is a hook I need to tell the bundler to load the
16:06
I need to tell the bundler to load the
16:06
I need to tell the bundler to load the JavaScript for this component with use
16:10
JavaScript for this component with use
16:10
JavaScript for this component with use client and I need to update my function
16:12
client and I need to update my function
16:13
client and I need to update my function that I'm passing here because use action
16:14
that I'm passing here because use action
16:14
that I'm passing here because use action State also passes a previous state
16:17
State also passes a previous state
16:17
State also passes a previous state argument to the function which I'm just
16:20
argument to the function which I'm just
16:20
argument to the function which I'm just going to say PR state I'm not going to
16:22
going to say PR state I'm not going to
16:22
going to say PR state I'm not going to use it now but we need to put it
16:24
use it now but we need to put it
16:24
use it now but we need to put it there and I'm just going to say message
16:27
there and I'm just going to say message
16:27
there and I'm just going to say message State here so we don't don't have to
16:29
State here so we don't don't have to
16:29
State here so we don't don't have to write types in this talk and all is good
16:34
write types in this talk and all is good
16:34
write types in this talk and all is good now so let's see what happens and I say
16:39
now so let's see what happens and I say
16:39
now so let's see what happens and I say hey and then
16:41
hey and then hi and now I hit my Max message count
16:44
hi and now I hit my Max message count
16:44
hi and now I hit my Max message count and I will get the return value of the
16:47
and I will get the return value of the
16:47
and I will get the return value of the submit message uh function to my
16:50
submit message uh function to my
16:50
submit message uh function to my component
16:53
here and uh you could check for anything
16:56
here and uh you could check for anything
16:56
here and uh you could check for anything when you're when you're doing um return
16:59
when you're when you're doing um return
16:59
when you're when you're doing um return something you can maybe return each
17:01
something you can maybe return each
17:01
something you can maybe return each error value for the form Fields but I
17:03
error value for the form Fields but I
17:03
error value for the form Fields but I just have one uh form field here so it's
17:05
just have one uh form field here so it's
17:05
just have one uh form field here so it's not really relevant in my case but you
17:06
not really relevant in my case but you
17:06
not really relevant in my case but you could do
17:08
could do that the next thing that I want to
17:10
that the next thing that I want to
17:10
that the next thing that I want to improve is make it feel a little bit
17:13
improve is make it feel a little bit
17:13
improve is make it feel a little bit more
17:14
more interative with this error message that
17:16
interative with this error message that
17:16
interative with this error message that I'm getting so I'm going to use an
17:20
I'm getting so I'm going to use an
17:20
I'm getting so I'm going to use an effect um to check if this state has an
17:24
effect um to check if this state has an
17:24
effect um to check if this state has an error and if it does I can just toast an
17:27
error and if it does I can just toast an
17:28
error and if it does I can just toast an error with that
17:29
error with that there and uh it's going to need a
17:31
there and uh it's going to need a
17:32
there and uh it's going to need a dependency array which is going to be
17:33
dependency array which is going to be
17:33
dependency array which is going to be the aor but also this time stamp that we
17:36
the aor but also this time stamp that we
17:36
the aor but also this time stamp that we created so that every time the time step
17:37
created so that every time the time step
17:37
created so that every time the time step changes we get a new
17:40
changes we get a new
17:40
changes we get a new toast so now when we get an error we're
17:43
toast so now when we get an error we're
17:43
toast so now when we get an error we're going to get also this toast
17:46
going to get also this toast
17:46
going to get also this toast here which means I don't need my error
17:49
here which means I don't need my error
17:49
here which means I don't need my error message at the bottom here anymore but
17:51
message at the bottom here anymore but
17:51
message at the bottom here anymore but instead of removing it I'm just going to
17:53
instead of removing it I'm just going to
17:53
instead of removing it I'm just going to leave it as a no script fallback which
17:56
leave it as a no script fallback which
17:56
leave it as a no script fallback which means that for some reason if there's no
17:57
means that for some reason if there's no
17:57
means that for some reason if there's no JavaScript you will still be able to see
18:00
JavaScript you will still be able to see
18:00
JavaScript you will still be able to see this
18:07
error um uh let's try fixing something else so
18:11
um uh let's try fixing something else so
18:11
um uh let's try fixing something else so when I submit uh and I hit this Max
18:14
when I submit uh and I hit this Max
18:14
when I submit uh and I hit this Max message count my form field has been
18:16
message count my form field has been
18:16
message count my form field has been cleared and the reason for that is
18:19
cleared and the reason for that is
18:19
cleared and the reason for that is because when you use react 19 form
18:21
because when you use react 19 form
18:21
because when you use react 19 form actions with uncontrolled inputs it will
18:24
actions with uncontrolled inputs it will
18:24
actions with uncontrolled inputs it will automatically reset the form for you
18:26
automatically reset the form for you
18:26
automatically reset the form for you when the action completes which is a
18:29
when the action completes which is a
18:29
when the action completes which is a good thing because it kind of mimics
18:30
good thing because it kind of mimics
18:30
good thing because it kind of mimics this NPA form submission behavior that
18:32
this NPA form submission behavior that
18:32
this NPA form submission behavior that we're used to in the more um old ways of
18:34
we're used to in the more um old ways of
18:34
we're used to in the more um old ways of writing forms with the
18:36
writing forms with the
18:36
writing forms with the web but uh in this case I want to leave
18:40
web but uh in this case I want to leave
18:40
web but uh in this case I want to leave it there because maybe if my form had
18:42
it there because maybe if my form had
18:42
it there because maybe if my form had been different the user would have been
18:43
been different the user would have been
18:43
been different the user would have been able to change this input or this value
18:45
able to change this input or this value
18:45
able to change this input or this value inside the input to something that would
18:47
inside the input to something that would
18:47
inside the input to something that would be valid and would submit and I don't
18:49
be valid and would submit and I don't
18:49
be valid and would submit and I don't want them to rewrite whatever they just
18:52
want them to rewrite whatever they just
18:52
want them to rewrite whatever they just wrote so what I'm going to do is when
18:56
wrote so what I'm going to do is when
18:56
wrote so what I'm going to do is when this error occurs I'm going to also
18:58
this error occurs I'm going to also
18:58
this error occurs I'm going to also return return the
19:00
return return the content and what I will do is use this
19:03
content and what I will do is use this
19:03
content and what I will do is use this as the default value of the
19:07
as the default value of the
19:07
as the default value of the form and maybe if you've been working
19:09
form and maybe if you've been working
19:09
form and maybe if you've been working with reactor form you used to making
19:11
with reactor form you used to making
19:11
with reactor form you used to making this controlled form State well this is
19:13
this controlled form State well this is
19:13
this controlled form State well this is just uncontrolled inputs and default
19:16
just uncontrolled inputs and default
19:16
just uncontrolled inputs and default value and now if I try to type something
19:20
value and now if I try to type something
19:20
value and now if I try to type something it will not reset my form or the default
19:22
it will not reset my form or the default
19:22
it will not reset my form or the default Val value will be the return value of
19:24
Val value will be the return value of
19:24
Val value will be the return value of this
19:27
data um um but what if the trip to the
19:31
data um um but what if the trip to the
19:31
data um um but what if the trip to the server back back is a bit
19:35
server back back is a bit
19:35
server back back is a bit slow so that's realistic because I'm
19:37
slow so that's realistic because I'm
19:37
slow so that's realistic because I'm just using a local database here it will
19:40
just using a local database here it will
19:40
just using a local database here it will take a bit of some time here for me to
19:43
take a bit of some time here for me to
19:43
take a bit of some time here for me to see uh the
19:45
see uh the response and maybe I would be
19:47
response and maybe I would be
19:47
response and maybe I would be accidentally submitting more messages so
19:49
accidentally submitting more messages so
19:49
accidentally submitting more messages so I need to uh handle that
19:52
I need to uh handle that
19:52
I need to uh handle that somehow and the use action State
19:54
somehow and the use action State
19:54
somehow and the use action State actually returns a third argument is
19:57
actually returns a third argument is
19:57
actually returns a third argument is pending or return third
20:00
pending or return third
20:00
pending or return third value which I can use um to disable my
20:06
value which I can use um to disable my
20:06
value which I can use um to disable my button and say something else here
20:09
button and say something else here
20:09
button and say something else here like uh
20:17
um what happened here let's try this
20:20
um what happened here let's try this
20:21
um what happened here let's try this again like that so now when it's being
20:24
again like that so now when it's being
20:24
again like that so now when it's being slow I will see that it's sending and I
20:27
slow I will see that it's sending and I
20:27
slow I will see that it's sending and I won't be able to click again
20:31
so um let's just increase this Max
20:35
so um let's just increase this Max
20:35
so um let's just increase this Max message count to eight and see the full
20:37
message count to eight and see the full
20:37
message count to eight and see the full interactive message box
20:39
interactive message box
20:39
interactive message box again so I'm going to just open this up
20:42
again so I'm going to just open this up
20:42
again so I'm going to just open this up and say hey and we'll see the sending
20:45
and say hey and we'll see the sending
20:45
and say hey and we'll see the sending the automatic scroll and the field form
20:48
the automatic scroll and the field form
20:48
the automatic scroll and the field form reset and this is just so much easier to
20:50
reset and this is just so much easier to
20:50
reset and this is just so much easier to handle than the pag rer uh form
20:53
handle than the pag rer uh form
20:53
handle than the pag rer uh form submission but uh what's good here is
20:56
submission but uh what's good here is
20:57
submission but uh what's good here is this whole form will actually work
20:58
this whole form will actually work
20:58
this whole form will actually work without JavaScript so let me just
21:00
without JavaScript so let me just
21:00
without JavaScript so let me just disable the JavaScript to see
21:03
disable the JavaScript to see
21:03
disable the JavaScript to see that so I will say no
21:07
JavaScript and uh it worked I didn't get
21:11
JavaScript and uh it worked I didn't get
21:11
JavaScript and uh it worked I didn't get any automa scrolling I
21:13
any automa scrolling I
21:13
any automa scrolling I um and um I didn't get any pending state
21:16
um and um I didn't get any pending state
21:16
um and um I didn't get any pending state but everything still
21:18
but everything still
21:18
but everything still worked say no
21:20
worked say no JS it's working still no
21:24
JS it's working still no
21:24
JS it's working still no JS and then I hit my Max message count
21:27
JS and then I hit my Max message count
21:27
JS and then I hit my Max message count and see this no script fall
21:30
and see this no script fall
21:30
and see this no script fall back so I'm just going to turn this back
21:33
back so I'm just going to turn this back
21:33
back so I'm just going to turn this back on and refresh
21:35
on and refresh here and go back to my uh initial
21:40
here and go back to my uh initial
21:40
here and go back to my uh initial view so what we've essentially been
21:42
view so what we've essentially been
21:42
view so what we've essentially been doing here is progressively enhancing
21:44
doing here is progressively enhancing
21:44
doing here is progressively enhancing this form meaning ensuring all the basic
21:47
this form meaning ensuring all the basic
21:47
this form meaning ensuring all the basic functionality works at the lowest level
21:48
functionality works at the lowest level
21:48
functionality works at the lowest level of resources and then which is no
21:51
of resources and then which is no
21:51
of resources and then which is no JavaScript and then adding things on top
21:53
JavaScript and then adding things on top
21:53
JavaScript and then adding things on top to enhance the user experience for users
21:55
to enhance the user experience for users
21:55
to enhance the user experience for users with those resources available so even
21:57
with those resources available so even
21:57
with those resources available so even if your users on a slow device or a slow
21:59
if your users on a slow device or a slow
21:59
if your users on a slow device or a slow connection they don't have to wait for
22:01
connection they don't have to wait for
22:01
connection they don't have to wait for JS to download parts and execute they
22:04
JS to download parts and execute they
22:04
JS to download parts and execute they can use the form while the page is still
22:06
can use the form while the page is still
22:06
can use the form while the page is still hydrating and since we reduce the js on
22:09
hydrating and since we reduce the js on
22:09
hydrating and since we reduce the js on the client with uh by limiting the JS in
22:11
the client with uh by limiting the JS in
22:11
the client with uh by limiting the JS in this automatic scroller the JS that we
22:14
this automatic scroller the JS that we
22:14
this automatic scroller the JS that we do want will load a lot
22:18
faster um there is however one more
22:20
faster um there is however one more
22:21
faster um there is however one more Improvement that I can make to this code
22:23
Improvement that I can make to this code
22:23
Improvement that I can make to this code so what I can do is I can extract this
22:26
so what I can do is I can extract this
22:26
so what I can do is I can extract this button into a submit button
22:31
so I want this to be a um composable and
22:34
so I want this to be a um composable and
22:34
so I want this to be a um composable and reusable way to get penden dat of a form
22:37
reusable way to get penden dat of a form
22:37
reusable way to get penden dat of a form going to say send here and I'm going to
22:39
going to say send here and I'm going to
22:39
going to say send here and I'm going to make it inside my UI UI
22:43
components and I'm just going to paste
22:46
components and I'm just going to paste
22:46
components and I'm just going to paste whatever was there inside
22:48
whatever was there inside
22:48
whatever was there inside here um and I need to get this pending
22:52
here um and I need to get this pending
22:52
here um and I need to get this pending state from somewhere so I'm going to use
22:55
state from somewhere so I'm going to use
22:55
state from somewhere so I'm going to use the new hook use form status
23:01
and it will return a couple of things
23:02
and it will return a couple of things
23:02
and it will return a couple of things you will get some data you will get a
23:04
you will get some data you will get a
23:04
you will get some data you will get a pending and a couple other things but we
23:06
pending and a couple other things but we
23:06
pending and a couple other things but we only need the pending here so I'm going
23:08
only need the pending here so I'm going
23:08
only need the pending here so I'm going to put that on my
23:10
to put that on my button and uh this has to be a client
23:13
button and uh this has to be a client
23:13
button and uh this has to be a client component because this is a
23:17
hook and you and it also needs some
23:20
hook and you and it also needs some
23:20
hook and you and it also needs some props which is going to be the
23:23
props which is going to be the
23:23
props which is going to be the children and if it's
23:26
children and if it's
23:26
children and if it's pending we can write render a nicely
23:29
pending we can write render a nicely
23:29
pending we can write render a nicely styled
23:31
styled div with the a
23:39
spinner and the children and otherwise we will just
23:42
children and otherwise we will just
23:42
children and otherwise we will just render the
23:46
children um let's see if I can make this
23:50
children um let's see if I can make this
23:50
children um let's see if I can make this correct I think that's good there we
23:54
correct I think that's good there we
23:54
correct I think that's good there we go so let's try to import it and see if
23:57
go so let's try to import it and see if
23:57
go so let's try to import it and see if it works
23:59
it works and I'm going to say hi and it's now
24:02
and I'm going to say hi and it's now
24:02
and I'm going to say hi and it's now using this submit button and it's
24:04
using this submit button and it's
24:04
using this submit button and it's handling everything for me the loading
24:06
handling everything for me the loading
24:06
handling everything for me the loading state is just there I'm just using a
24:07
state is just there I'm just using a
24:07
state is just there I'm just using a submit
24:08
submit button and what's so great about this is
24:10
button and what's so great about this is
24:10
button and what's so great about this is I can throw this into any component like
24:12
I can throw this into any component like
24:12
I can throw this into any component like I can go to the message box and just
24:16
I can go to the message box and just
24:16
I can go to the message box and just toss it in there make it form with an
24:18
toss it in there make it form with an
24:18
toss it in there make it form with an action to reset my
24:25
messages um and I can just make an in line
24:28
um and I can just make an in line
24:28
um and I can just make an in line function
24:29
function here reset messages it's going to be a
24:32
here reset messages it's going to be a
24:32
here reset messages it's going to be a server action it's going to be
24:35
server action it's going to be
24:36
server action it's going to be slow it's going to delete messages from
24:39
slow it's going to delete messages from
24:39
slow it's going to delete messages from my database and it's going to revalidate
24:41
my database and it's going to revalidate
24:41
my database and it's going to revalidate the
24:46
path and if I now import all the things
24:48
path and if I now import all the things
24:48
path and if I now import all the things that I
24:50
that I need and there we go we can see what
24:54
need and there we go we can see what
24:54
need and there we go we can see what happens so this is server component I
24:56
happens so this is server component I
24:56
happens so this is server component I don't have any use client here and still
24:59
don't have any use client here and still
24:59
don't have any use client here and still this submit button is handling the
25:00
this submit button is handling the
25:00
this submit button is handling the entire uh interactive feedback here for
25:04
entire uh interactive feedback here for
25:04
entire uh interactive feedback here for me and one more thing uh I want to show
25:08
me and one more thing uh I want to show
25:08
me and one more thing uh I want to show is the use
25:09
is the use optimistic so let's just get rid of all
25:12
optimistic so let's just get rid of all
25:12
optimistic so let's just get rid of all this code and uh jump over to an
25:14
this code and uh jump over to an
25:14
this code and uh jump over to an optimistic Branch really
25:17
optimistic Branch really
25:17
optimistic Branch really quick and in here I haven't done that
25:20
quick and in here I haven't done that
25:20
quick and in here I haven't done that much but I've made a messages component
25:23
much but I've made a messages component
25:23
much but I've made a messages component which is client component because it's
25:24
which is client component because it's
25:24
which is client component because it's using the use optimistic cook and what
25:27
using the use optimistic cook and what
25:27
using the use optimistic cook and what this does is take in a state to show
25:29
this does is take in a state to show
25:29
this does is take in a state to show when no action is pending which is going
25:31
when no action is pending which is going
25:31
when no action is pending which is going to be our truth from the server and an
25:34
to be our truth from the server and an
25:34
to be our truth from the server and an update function which says that an
25:35
update function which says that an
25:35
update function which says that an optimistic message will have an is
25:37
optimistic message will have an is
25:37
optimistic message will have an is sending
25:39
sending true and then I'm going to pass the
25:41
true and then I'm going to pass the
25:41
true and then I'm going to pass the function to update uh to trigger the
25:43
function to update uh to trigger the
25:43
function to update uh to trigger the optimistic update uh to my message input
25:45
optimistic update uh to my message input
25:45
optimistic update uh to my message input and also use the optimistic messages for
25:47
and also use the optimistic messages for
25:47
and also use the optimistic messages for my
25:48
my display and in the message input I'm
25:51
display and in the message input I'm
25:51
display and in the message input I'm just doing the optimistic update in an
25:53
just doing the optimistic update in an
25:53
just doing the optimistic update in an unsubmit while leaving the uh action as
25:56
unsubmit while leaving the uh action as
25:56
unsubmit while leaving the uh action as a fallback
25:59
a fallback so let's just see how that feels when I
26:01
so let's just see how that feels when I
26:01
so let's just see how that feels when I say hey I'm getting optimistic uh
26:05
say hey I'm getting optimistic uh
26:05
say hey I'm getting optimistic uh everything's happening right away and I
26:06
everything's happening right away and I
26:06
everything's happening right away and I get the sending here while the server is
26:09
get the sending here while the server is
26:09
get the sending here while the server is settling and replacing the client state
26:12
settling and replacing the client state
26:12
settling and replacing the client state with the message that does not have the
26:14
with the message that does not have the
26:14
with the message that does not have the ascending
26:17
flag hi and as you can see we're having
26:19
hi and as you can see we're having
26:19
hi and as you can see we're having optimistic optimistic messages all
26:22
optimistic optimistic messages all
26:22
optimistic optimistic messages all resolving can send a couple more and
26:25
resolving can send a couple more and
26:25
resolving can send a couple more and when I hit my Max message count here
26:28
when I hit my Max message count here
26:28
when I hit my Max message count here the optimistic message will be roll back
26:32
the optimistic message will be roll back
26:32
the optimistic message will be roll back because it does not exist in the service
26:34
because it does not exist in the service
26:34
because it does not exist in the service state and this is all still Progressive
26:36
state and this is all still Progressive
26:36
state and this is all still Progressive enhanced by the
26:38
enhanced by the way so uh of course depending on the app
26:40
way so uh of course depending on the app
26:40
way so uh of course depending on the app you don't have to make progressiv
26:42
you don't have to make progressiv
26:42
you don't have to make progressiv enhanced forms or anything like that but
26:44
enhanced forms or anything like that but
26:44
enhanced forms or anything like that but now by using these more primitive
26:46
now by using these more primitive
26:46
now by using these more primitive features of react 19 um with react react
26:49
features of react 19 um with react react
26:49
features of react 19 um with react react surf components we can make our forms
26:51
surf components we can make our forms
26:52
surf components we can make our forms very robust while maintaining a great
26:53
very robust while maintaining a great
26:53
very robust while maintaining a great user
26:55
user experience and these are probably going
26:56
experience and these are probably going
26:56
experience and these are probably going to be used as Primitives for other
26:58
to be used as Primitives for other
26:58
to be used as Primitives for other Library authors to U make for example
27:00
Library authors to U make for example
27:00
Library authors to U make for example form libraries that make it easier for
27:01
form libraries that make it easier for
27:01
form libraries that make it easier for us normal
27:03
us normal developers I'm almost done here I'm just
27:05
developers I'm almost done here I'm just
27:05
developers I'm almost done here I'm just going to quickly round it off um by
27:08
going to quickly round it off um by
27:08
going to quickly round it off um by saying that form actions exist in other
27:11
saying that form actions exist in other
27:12
saying that form actions exist in other Frameworks as well but now we have them
27:14
Frameworks as well but now we have them
27:14
Frameworks as well but now we have them in next and it's great we can make do a
27:17
in next and it's great we can make do a
27:17
in next and it's great we can make do a lot more than we could before with a lot
27:18
lot more than we could before with a lot
27:18
lot more than we could before with a lot more code a lot less code
27:22
more code a lot less code
27:22
more code a lot less code sorry and the repo for uh the demo is
27:25
sorry and the repo for uh the demo is
27:25
sorry and the repo for uh the demo is here on GitHub uh and then the optim
27:28
here on GitHub uh and then the optim
27:28
here on GitHub uh and then the optim update is in a branch if you want to
27:29
update is in a branch if you want to
27:29
update is in a branch if you want to check that
27:32
out and references uh most of what I've
27:35
out and references uh most of what I've
27:35
out and references uh most of what I've done is just from exam it can just be
27:37
done is just from exam it can just be
27:37
done is just from exam it can just be found in the docs and the react docs
27:40
found in the docs and the react docs
27:40
found in the docs and the react docs have more in-depth explanations and also
27:41
have more in-depth explanations and also
27:41
have more in-depth explanations and also considering the client side more than
27:43
considering the client side more than
27:43
considering the client side more than just the server that the xgf
27:46
just the server that the xgf
27:46
just the server that the xgf stocks uh yes I have a Twitter I post RC
27:49
stocks uh yes I have a Twitter I post RC
27:49
stocks uh yes I have a Twitter I post RC there excuse me RC stuff there and a
27:52
there excuse me RC stuff there and a
27:52
there excuse me RC stuff there and a Blog so if you're interested in learning
27:54
Blog so if you're interested in learning
27:54
Blog so if you're interested in learning more check that out thank you