1
00:00:03,000 --> 00:00:05,491
We're now using "force-dynamic"

2
00:00:05,491 --> 00:00:08,617
to make sure all the pages where we fetch data

3
00:00:08,617 --> 00:00:11,939
display the latest content from the CMS.

4
00:00:11,939 --> 00:00:16,359
This forces each page to be re-rendered at runtime

5
00:00:16,359 --> 00:00:18,318
every time we request it.

6
00:00:18,318 --> 00:00:20,249
Now, before we move on to

7
00:00:20,249 --> 00:00:22,344
more sophisticated ways of

8
00:00:22,344 --> 00:00:24,438
dealing with data changes,

9
00:00:24,519 --> 00:00:27,245
there's something else we need to think about.

10
00:00:27,245 --> 00:00:30,971
Given that this ReviewPage is rendered on demand

11
00:00:30,971 --> 00:00:34,520
fetching the data for the given slug from the CMS,

12
00:00:34,520 --> 00:00:36,945
what happens if somebody requests

13
00:00:36,945 --> 00:00:38,856
a slug that doesn't exist,

14
00:00:38,929 --> 00:00:41,319
like "xyz" for example?

15
00:00:41,319 --> 00:00:45,421
Ideally, you'd expect our app to return a 404 page,

16
00:00:45,421 --> 00:00:45,903
right?

17
00:00:45,984 --> 00:00:48,403
But what actually happens at the moment

18
00:00:48,403 --> 00:00:50,691
is that we see an ugly error.

19
00:00:50,691 --> 00:00:52,497
If we look in the server logs,

20
00:00:52,497 --> 00:00:54,024
what's happening is that

21
00:00:54,024 --> 00:00:57,083
our "ReviewPage" component is rendered

22
00:00:57,083 --> 00:00:58,934
with "xyz" as the slug,

23
00:00:59,014 --> 00:01:02,435
but since there is no such review in the CMS

24
00:01:02,435 --> 00:01:05,400
we end up with an "item" that's "undefined",

25
00:01:05,400 --> 00:01:07,676
and our code fails when trying to

26
00:01:07,676 --> 00:01:09,813
read its "attributes" property.

27
00:01:09,882 --> 00:01:11,919
So clearlyÂ we need to handle

28
00:01:11,919 --> 00:01:13,955
this error condition better.

29
00:01:14,028 --> 00:01:16,673
We can use the "dev" server for this,

30
00:01:16,673 --> 00:01:18,562
which in fact works similarly

31
00:01:18,562 --> 00:01:20,125
to the production server

32
00:01:20,191 --> 00:01:22,400
when using dynamic rendering.

33
00:01:22,611 --> 00:01:25,174
The dev server shows the same error

34
00:01:25,174 --> 00:01:27,270
just with a few more details,

35
00:01:27,270 --> 00:01:29,603
and it also displays an overlay

36
00:01:29,603 --> 00:01:31,184
window over the page,

37
00:01:31,259 --> 00:01:33,202
to make sure we don't miss it.

38
00:01:33,202 --> 00:01:35,182
Anyway, the problem is that in

39
00:01:35,182 --> 00:01:37,161
this page we call "getReview".

40
00:01:37,226 --> 00:01:39,560
In that function we call the CMS

41
00:01:39,560 --> 00:01:41,672
and then take the first "item"

42
00:01:41,672 --> 00:01:43,221
from the "data" array.

43
00:01:43,291 --> 00:01:45,429
But if the "slug" we requested

44
00:01:45,429 --> 00:01:47,211
doesn't match any reviews

45
00:01:47,282 --> 00:01:50,086
then the "data" array will be empty.

46
00:01:50,086 --> 00:01:52,417
So before taking the first element

47
00:01:52,417 --> 00:01:54,649
we need to check if "data"

48
00:01:54,649 --> 00:01:56,796
has "length" equals zero.

49
00:01:56,882 --> 00:01:59,692
In this case we could simply return "null",

50
00:01:59,692 --> 00:02:02,926
to indicate that there is no such review.

51
00:02:02,926 --> 00:02:05,206
At this point there's still an error,

52
00:02:05,206 --> 00:02:07,424
but it's no longer in this function.

53
00:02:07,485 --> 00:02:10,616
We now need to update the page code as well,

54
00:02:10,616 --> 00:02:12,828
and after calling "getReview"

55
00:02:12,828 --> 00:02:15,984
check if we actually got a result or not.

56
00:02:16,164 --> 00:02:18,201
If the "review" doesn't exist

57
00:02:18,201 --> 00:02:22,013
then we should somehow return a 404 error.

58
00:02:22,013 --> 00:02:25,004
We can do that by importing a special function

59
00:02:25,485 --> 00:02:28,729
from the "next/navigation" module.

60
00:02:28,729 --> 00:02:31,916
This provides a function called "notFound",

61
00:02:31,916 --> 00:02:35,298
that we can use precisely in these situations.

62
00:02:35,298 --> 00:02:37,884
We can simply call "notFound" here,

63
00:02:37,884 --> 00:02:40,019
without actually returning early,

64
00:02:40,019 --> 00:02:43,150
because calling this function will automatically

65
00:02:43,150 --> 00:02:45,367
stop the normal rendering process,

66
00:02:45,433 --> 00:02:48,462
and return a 404 page instead.

67
00:02:48,462 --> 00:02:50,705
Now, we need to do this check

68
00:02:50,705 --> 00:02:53,028
not just in "generateMetadata"

69
00:02:53,028 --> 00:02:55,731
but also inside the function component,

70
00:02:55,731 --> 00:02:57,770
because we call "getReview"

71
00:02:57,770 --> 00:02:59,809
in two places in this file.

72
00:02:59,884 --> 00:03:03,152
If you remember, "generateMetadata" is used

73
00:03:03,152 --> 00:03:06,741
to set the "title" tag in the HTML head,

74
00:03:06,741 --> 00:03:09,700
while the ReviewPage function of course

75
00:03:09,700 --> 00:03:11,976
renders the main page content.

76
00:03:12,052 --> 00:03:14,337
Anyway, if we save this change

77
00:03:14,337 --> 00:03:17,407
we now see a 404 page in the browser.

78
00:03:17,407 --> 00:03:21,983
So we are now properly handling non-existent URLs.

79
00:03:21,983 --> 00:03:25,420
Note that this 404 page is the default

80
00:03:25,420 --> 00:03:27,591
one provided by Next.js.

81
00:03:27,682 --> 00:03:31,460
Although it is rendered inside our RootLayout.

82
00:03:31,460 --> 00:03:35,730
But we can also customize the 404 page if we want.

83
00:03:35,730 --> 00:03:38,058
All we need to do is create a new

84
00:03:38,058 --> 00:03:40,105
file inside the "app" folder,

85
00:03:40,175 --> 00:03:43,763
called "not-found.jsx".

86
00:03:43,763 --> 00:03:46,563
This is a special page that will

87
00:03:46,563 --> 00:03:48,838
be used for 404 responses.

88
00:03:48,925 --> 00:03:52,070
Let me copy some code from the AboutPage

89
00:03:52,070 --> 00:03:55,871
just as a starting point for the Not Found one.

90
00:03:55,871 --> 00:03:58,111
Even though it has a special name,

91
00:03:58,111 --> 00:04:01,659
this file must also export a React component.

92
00:04:01,659 --> 00:04:04,939
Let me just rename it to "NotFoundPage",

93
00:04:04,939 --> 00:04:08,670
and we need to import the "Heading" component.

94
00:04:08,670 --> 00:04:12,175
Let's change the text to "Not Found" as well.

95
00:04:12,175 --> 00:04:15,268
And then we could show a custom message here,

96
00:04:15,268 --> 00:04:18,315
let's say: "Oops, the page you requested"

97
00:04:18,588 --> 00:04:21,257
"only exists in a parallel universe."

98
00:04:21,595 --> 00:04:24,181
Just to make our Not Found page a bit funnier.

99
00:04:24,181 --> 00:04:27,686
If we try and open "/reviews/xyz" now

100
00:04:27,686 --> 00:04:30,983
we can see our custom Not Found page.

101
00:04:30,983 --> 00:04:33,343
Ok, so this is how we can

102
00:04:33,343 --> 00:04:35,702
provide our own 404 page.

103
00:04:35,797 --> 00:04:37,796
But, perhaps more importantly,

104
00:04:37,796 --> 00:04:39,172
we've also seen how

105
00:04:39,172 --> 00:04:42,645
we need to call the special "notFound" function

106
00:04:42,645 --> 00:04:44,911
whenever we cannot render a page

107
00:04:44,911 --> 00:04:48,037
because the requested data doesn't exist.

