We've seen before, in the section on Rendering,
that if we need to use any
client-side functionality,
we need to add the "use client" directive
at the top of the file,
to mark this as a Client Component.
With this simple change, the error goes away.
But let's make sure we fully understand
what's going on here.
If we comment out the "use client" directive,
then this will be treated a Server Component,
and if we save, we get an error,
because we cannot use client-side functionality
in a Server Component.
Note that the error started when
we added the "onClick" handler.
If we remove this, then everything
works just fine,
because there's no longer any
client-side functionality,
and so this component can be
rendered only on the server.
Let's add a log statement here,
printing a message any time
this component is rendered,
just to remind ourselves of how rendering works.
By default, all our components
are Server Components,
meaning that they only render on the server.
There are no messages in the browser console.
With the "use client" directive however,
ShareLinkButton will be treated
as a Client Component.
This means that it will be rendered
both on the server and in the browser.
Let's see how this works in
terms of network requests.
I'll comment out "use client" again,
so we can start with the Server
Component behavior.
If we look at the Network requests,
when we open the page,
we know that the browser first
loads the HTML document.
And the Next.js server pre-renders
the HTML for all our components,
including ShareLinkButton.
Since it's currently a Server Component,
no JavaScript code will be sent to
the browser for this component.
So we see the button displayed on the page,
as rendered from this HTML code,
but we cannot have any actual functionality
attached to the button,
because the browser doesn't have any JavaScript
code associated with that component.
Now, let's turn it into a Client Component again,
and see what happens if we reload the page.
The first request will still be the HTML document,
and the ShareLinkButton was still
pre-rendered on the server.
However, since it's now a Client Component,
the browser will also receive
some JavaScript code,
that should include the function where
we log the "clicked" message.
This code contains the full
ShareLinkButton function.
After loading this JavaScript file,
the browser runs the component function,
rendering our component on the client-side.
In fact, in this function we
log a message to the console
saying "rendering".
And we do see that message printed
to the browser console,
proving that the browser is executing
our ShareLinkButton function.
So, the browser has the full
code for this component.
That's why we can now include
client-side functionality,
like an "onClick" handler for the button.
If we reload the page,
when we click the button we'll see that
our handler function is called,
and logs the "clicked" message.
Of course, it will be called again
whenever we click the button.
Now, the process of rendering
a component in the browser,
after it was already pre-rendered on the server,
is called "hydration".
It is a bit different from rendering
a component only in the browser,
like in traditional React
Single Page Applications,
because in this case we already
have some initial HTML,
generated by the server,
with all the elements for our
ShareLinkButton for example.
After loading and displaying that initial HTML,
the browser will then load the JavaScript code.
And it will execute our component function,
rendering a client-side version
of the same component.
It will be almost the same as the
HTML pre-rendered by the server,
but with an important difference:
the elements can have event handlers attached,
like the "handleClick" function associated
to the button "onClick" event.
So at this point the browser
needs to somehow merge
the elements already displayed on the page
from the initial HTML generated by the server,
with the elements rendered on the client side.
This is what the "hydration" process does.
The result will be
the same HTML elements pre-rendered by the server
but with the addition of event handlers,
and all the JavaScript code associated
with our component.
So at this point we have some
fully-interactive elements,
like a button that can actually do
something when the user clicks it.