1
00:00:03,000 --> 00:00:05,131
Ok, so we're trying to read a value

2
00:00:05,131 --> 00:00:06,349
from "localStorage",

3
00:00:06,910 --> 00:00:08,648
but we're getting an error

4
00:00:08,648 --> 00:00:11,457
saying that "localStorage is not defined".

5
00:00:12,024 --> 00:00:13,891
Let's make sure we fully understand

6
00:00:13,891 --> 00:00:15,012
what's going on here.

7
00:00:15,566 --> 00:00:17,371
When we run our JavaScript code

8
00:00:17,371 --> 00:00:18,245
in the browser,

9
00:00:18,245 --> 00:00:20,342
and I'll use the interactive console

10
00:00:20,342 --> 00:00:21,391
to demonstrate it,

11
00:00:22,066 --> 00:00:23,700
there is a global object

12
00:00:23,700 --> 00:00:25,199
called "localStorage",

13
00:00:25,199 --> 00:00:27,311
which happens to be an instance

14
00:00:27,311 --> 00:00:29,014
of the Storage interface.

15
00:00:29,719 --> 00:00:32,356
But when our code run on the server

16
00:00:32,356 --> 00:00:33,788
it runs in Node.js,

17
00:00:34,364 --> 00:00:35,738
and if we try accessing

18
00:00:35,738 --> 00:00:37,233
"localStorage" from here,

19
00:00:37,233 --> 00:00:38,189
we get an error.

20
00:00:38,809 --> 00:00:40,935
Which is in fact exactly the same error

21
00:00:40,935 --> 00:00:42,298
we got in our application

22
00:00:42,853 --> 00:00:45,844
when trying to read the "darkMode" value.

23
00:00:45,844 --> 00:00:48,179
Our "loadDarkMode" function runs

24
00:00:48,752 --> 00:00:51,768
in two different JavaScript environments:

25
00:00:51,768 --> 00:00:53,387
Node.js on the server,

26
00:00:53,387 --> 00:00:54,785
and in the browser.

27
00:00:54,785 --> 00:00:56,697
Local Storage is a web API

28
00:00:56,697 --> 00:00:59,420
that's only available in the browser.

29
00:00:59,420 --> 00:01:01,259
So before we try using it

30
00:01:01,259 --> 00:01:03,834
we need to check if it's available.

31
00:01:04,775 --> 00:01:06,141
A good way to do that

32
00:01:06,141 --> 00:01:08,221
is to use the "typeof" operator.

33
00:01:08,787 --> 00:01:09,721
In the browser,

34
00:01:09,721 --> 00:01:11,900
"localStorage" is of type "object".

35
00:01:12,463 --> 00:01:15,204
While if we try the same thing in Node.js

36
00:01:16,796 --> 00:01:19,182
we can see that here "localStorage"

37
00:01:19,182 --> 00:01:20,204
is "undefined".

38
00:01:20,773 --> 00:01:22,672
Now, let me quit the interpreter,

39
00:01:22,672 --> 00:01:24,226
and restart the dev server.

40
00:01:26,006 --> 00:01:28,012
So we want to do the same check

41
00:01:28,012 --> 00:01:30,019
in our "loadDarkMode" function.

42
00:01:30,584 --> 00:01:32,288
If "typeof localStorage"

43
00:01:32,288 --> 00:01:33,282
is "undefined"

44
00:01:33,282 --> 00:01:35,200
then this effectively means

45
00:01:35,200 --> 00:01:37,188
we're running on the server.

46
00:01:37,902 --> 00:01:39,662
In this case we can return

47
00:01:39,662 --> 00:01:42,031
a default value for the "darkMode",

48
00:01:42,031 --> 00:01:43,114
that is "false".

49
00:01:43,750 --> 00:01:46,261
This means the static HTML pages

50
00:01:46,261 --> 00:01:48,067
generated on the server

51
00:01:48,067 --> 00:01:50,579
will always use the light theme.

52
00:01:51,236 --> 00:01:52,523
With this small change

53
00:01:52,523 --> 00:01:53,985
the error should go away.

54
00:01:54,602 --> 00:01:55,839
You can see that the page

55
00:01:55,839 --> 00:01:57,077
is rendered successfully,

56
00:01:57,627 --> 00:01:59,736
and it has a dark background,

57
00:01:59,736 --> 00:02:02,500
so it used the saved "darkMode" value.

58
00:02:03,073 --> 00:02:04,044
We can test that

59
00:02:04,044 --> 00:02:05,744
everything else still works.

60
00:02:05,744 --> 00:02:07,080
If we click the button

61
00:02:07,080 --> 00:02:09,205
of course it will toggle the theme,

62
00:02:09,205 --> 00:02:11,453
and update the value in localStorage.

63
00:02:12,196 --> 00:02:14,466
So, remember that with Next.js,

64
00:02:14,466 --> 00:02:17,835
whenever you use some browser-specific feature

65
00:02:17,835 --> 00:02:20,472
in code that also runs in the server

66
00:02:21,119 --> 00:02:22,490
you should first check

67
00:02:22,490 --> 00:02:24,298
if that feature is available.

68
00:02:24,861 --> 00:02:27,428
Note that in the "handleClick" function

69
00:02:27,428 --> 00:02:29,008
there's no need to check

70
00:02:29,008 --> 00:02:31,050
if "localStorage" is available,

71
00:02:31,050 --> 00:02:33,025
because the button click event

72
00:02:33,025 --> 00:02:35,000
can only occur in the browser,

73
00:02:35,000 --> 00:02:37,765
so this code will never run on the server.

74
00:02:38,595 --> 00:02:40,668
Anyway, we're not quite finished yet.

75
00:02:40,668 --> 00:02:42,573
If we look at the browser console,

76
00:02:42,573 --> 00:02:44,365
there seems to be another error.

77
00:02:44,978 --> 00:02:46,535
Let me refresh the page,

78
00:02:46,535 --> 00:02:48,223
to show when that happens.

79
00:02:48,944 --> 00:02:50,398
It's not strictly an error,

80
00:02:50,398 --> 00:02:51,692
it's actually a warning,

81
00:02:51,692 --> 00:02:53,416
but it's a very interesting one.

82
00:02:54,024 --> 00:02:57,147
It says "Text content did not match."

83
00:02:57,147 --> 00:02:58,750
"Server: Dark Mode"

84
00:02:58,750 --> 00:03:00,439
"Client: Light Mode"

85
00:03:01,108 --> 00:03:02,674
Remember all our discussion

86
00:03:02,674 --> 00:03:04,994
about "hydration" in the previous video?

87
00:03:05,553 --> 00:03:07,021
That will help us understand

88
00:03:07,021 --> 00:03:08,175
what's happening here.

89
00:03:08,728 --> 00:03:10,000
Let me show the server logs,

90
00:03:11,061 --> 00:03:12,084
and add a divider.

91
00:03:12,961 --> 00:03:14,942
Now, we said many times that

92
00:03:14,942 --> 00:03:16,429
when we load the page

93
00:03:16,429 --> 00:03:19,119
first it's pre-rendered on the server,

94
00:03:19,119 --> 00:03:20,322
and on the server

95
00:03:20,322 --> 00:03:22,870
"darkMode" is always set to "false".

96
00:03:23,654 --> 00:03:25,403
Then our React component

97
00:03:25,403 --> 00:03:27,590
is re-rendered in the browser.

98
00:03:27,590 --> 00:03:30,142
Or more accurately it's "hydrated".

99
00:03:30,142 --> 00:03:33,568
But in the browser "darkMode" is set to "true",

100
00:03:33,568 --> 00:03:35,901
because its value is initialised

101
00:03:35,901 --> 00:03:37,359
from Local Storage".

102
00:03:38,224 --> 00:03:40,574
So there is a discrepancy compared to

103
00:03:40,574 --> 00:03:42,606
what was rendered by the server.

104
00:03:43,170 --> 00:03:45,101
In the initial static HTML

105
00:03:45,101 --> 00:03:48,443
the text inside the "button" was "Dark Mode",

106
00:03:49,018 --> 00:03:50,790
but when the same component

107
00:03:50,790 --> 00:03:52,562
is rendered in the browser,

108
00:03:52,562 --> 00:03:54,334
the text says "Light Mode".

109
00:03:54,966 --> 00:03:57,046
So during the hydration phase

110
00:03:57,046 --> 00:03:58,625
React tries to connect

111
00:03:58,625 --> 00:04:00,418
our ThemeSwitch component

112
00:04:00,418 --> 00:04:02,355
to the existing DOM element

113
00:04:02,355 --> 00:04:03,719
but it detects that

114
00:04:03,719 --> 00:04:05,369
something is different.

115
00:04:06,228 --> 00:04:08,019
That's why it prints that warning

116
00:04:08,019 --> 00:04:09,484
that we see in the console.

117
00:04:10,039 --> 00:04:11,864
It's basically React telling us

118
00:04:11,864 --> 00:04:13,926
something unusual is going on here;

119
00:04:14,485 --> 00:04:15,660
you may want to check if

120
00:04:15,660 --> 00:04:17,277
there's a problem with your code.

121
00:04:18,817 --> 00:04:19,611
But if we do go

122
00:04:19,611 --> 00:04:20,721
and look at our code,

123
00:04:21,884 --> 00:04:23,445
we'll see that actually

124
00:04:23,445 --> 00:04:25,889
there is nothing wrong in this case.

125
00:04:25,889 --> 00:04:27,723
The text inside this button

126
00:04:27,723 --> 00:04:29,284
can indeed be different

127
00:04:29,284 --> 00:04:31,118
between server and browser,

128
00:04:31,118 --> 00:04:32,611
and for a good reason.

129
00:04:32,611 --> 00:04:35,938
If "darkMode" was saved as "true" in localStorage

130
00:04:35,938 --> 00:04:37,772
the browser should override

131
00:04:37,772 --> 00:04:40,148
the initial text set by the server,

132
00:04:40,148 --> 00:04:41,913
and that's perfectly fine.

133
00:04:43,025 --> 00:04:44,663
So as long as we're sure

134
00:04:44,663 --> 00:04:46,232
that it's not a problem

135
00:04:46,232 --> 00:04:48,621
we can set a special React property

136
00:04:48,621 --> 00:04:50,942
called "suppressHydrationWarning".

137
00:04:51,647 --> 00:04:53,615
Which does exactly what it says:

138
00:04:53,615 --> 00:04:55,398
it makes the warning go away.

139
00:04:55,960 --> 00:04:57,484
But we should only use this

140
00:04:57,484 --> 00:04:58,444
in special cases.

141
00:04:59,001 --> 00:05:01,327
With this our example is complete.

142
00:05:01,327 --> 00:05:03,174
We've seen how to implement

143
00:05:03,174 --> 00:05:05,227
some client side functionality

144
00:05:05,227 --> 00:05:06,116
with Next.js.

145
00:05:06,822 --> 00:05:08,443
It's mostly the same as

146
00:05:08,443 --> 00:05:10,065
with normal React apps,

147
00:05:10,065 --> 00:05:11,758
but there are some cases

148
00:05:11,758 --> 00:05:13,803
where we need to keep in mind

149
00:05:13,803 --> 00:05:16,483
that our code also runs on the server,

150
00:05:16,483 --> 00:05:18,669
to pre-render our static pages.

