Now at the moment,
this application has some minor problems.
Most importantly, if I select a month here,
we don't get any feedback initially
until the data is loaded,
which takes a while, and we got no feedback
whilst we're waiting for the data.
And that might be strange.
Why are we getting no loading feedback when loading a month,
even though we of course have a parent loading JS file?
Well, we're not getting any feedback
because when selecting a month,
we already are on that filter page here,
and therefore NextJS does not swap it
for the loading fallback
since we already have some data here.
We're just loading some new data,
but we already did load data before,
so it's not showing us that loading fallback again.
Now we can work around that
by using a more granular approach
of showing a loading fallback,
an alternative to using the loading JS file,
which, you by the way, can always use as an alternative,
not just in situations like this.
And that alternative
uses the suspense component that is provided by React
to tell NextJS in detail
for which kind of data we wanna wait
and under which circumstances
a loading fallback should be shown.
Now, how can we use suspense for that?
Well, as a first step,
we have to create a separate component,
and we can do that in a separate file
or in the same file as this page component.
And here I'll just use that same file
to keep those things together.
Now you can give this component any name of your choice.
I'll name it FilteredNews.
Now here in this component,
I'll of course get a props object
and I expect up to two props to be passed to this component,
the selected year
or maybe just year to keep it a bit shorter
and the selected month,
though both might be undefined.
And then in the end, I wanna move that code
where I get the news forward a year
out of the filtered news page
into the filtered news component.
And therefore this should become an async component,
which it can,
because all components, not just page components,
are server components by default in NextJS.
So I'll create that news variable
and then I check if we have a year
and we don't have a month.
And in that case, I'll set my news to the news
for a selected year,
though it's no longer called selected year here,
but instead just year.
Else if we have a year and a month.
So if we have both, news should be set equal to get news
for a year and month,
and I pass both the year and the month to that function.
So now with that, I'm fetching my news like this,
and then I wanna output that news list
just as I did it before.
So I'll actually grab this code
where I also render some fallback
in case we don't have any news
and I'll cut this and add this here.
And then I can just return
that news content here like this.
Now we should clean up the filtered news page.
And there I still wanna extract
the selected year and selected month,
but we no longer need the news variable here
and we also won't populate it here therefore.
And I'll actually also improve this code a little bit
and not fetch the same information twice.
But instead, I'll just fetch my available years here
and then use that fetched value
as a default value for my links like this.
And I now don't wanna output the news content here,
but instead this newly added filtered news component
to which we pass a year prop,
which is set equal to selected year
and a month prop, which is set equal to selected month.
Now with that alone, nothing would change.
If I now reload this page,
we are still loading the data for a selected year
and I can load the data for a selected month,
but I still get no loading fallback.
But now that we outsourced this data fetching logic
where we fetched and use for a year or month
into a separate React Server component,
we can use that React suspense hook I mentioned before.
So for that, we now wrap suspense around the component
that does the data fetching
for which we want to provide our own custom loading fallback
and suspense must be imported from React.
So you must import this component.
And with it being wrapped around a component
that fetches data,
it will automatically register
if that component is still fetching data
and it allows us to show a fallback whilst that's the case.
So here I can then say loading news or something like this.
And with that, we then have a very granular way
of telling NextJS that a part of the JSX code
should be replaced with a fallback
if that part is fetching data.
With loading.js, it's less granular.
There we're telling NextJS
that an entire component, the entire page component actually
should be replaced with that fallback if it's fetching data.
But if we're then just re fetching data,
it will not be replaced again.
And if we want it to be more granular in general,
we couldn't do it with a loading JS file,
but we can be very granular
by defining our own suspense boundaries.
And therefore, with this added now,
if I now reload, we got the same effect as before,
but now you already see,
we got the loading use fallback here,
and if I now click on a month,
we also see loading use here until the month appears.
Though, as you can see,
it actually still takes a short while
until we see that fallback after I clicked on a month.
And that's happening because technically NextJS
is re rendering this page when we click on a month
because we did change the route parameters
and therefore it does re fetch the data for the header
that's shown above the news list.
And hence, for example, again,
gets the available news years.
And therefore we might wanna wrap this header
with a suspense boundary as well
so that we actually add another component.
And again, we could outsource them into separate files,
but since they do belong directly to this page,
I'll keep them in the same file here for now.
And I'll name this component Filter
or FilterHeader, whatever.
And this should also become a async component
because it also is a React server component.
And now we can grab this code here
where we set up the links
and cut that from the filtered news page,
and instead add it here to the filter header
and expect to get the year at month that was selected
through the route parameters here as well.
And then use month instead of selected month
and year instead of selected year like this.
And then of course also output that header.
So here, I'll grab that header JSX code and cut it,
and then go back here to my filter header
and return it here like this.
And now we can use the filter header
in the filtered news page like this.
And of course, all the past year and month to that.
And again, we can now wrap this with suspense
and say loading filter.
But now we'll show different loading fallbacks
for these different areas.
And if they take different amounts of times to load,
we'll show content as soon as it's ready
because these two suspense boundaries
do not wait on each other.
Instead, each boundary will show its data once it's there
and show its fallback until it's there,
but it does not wait for any other data
in any other suspense wrapped component to load.
That's really great,
and that gives you a really granular way
of showing a fallback
and handling the loading state of data
in your page components.
Now of course, here in my code,
I actually still need to know about those available years
to potentially show an error if we have an invalid filter,
but actually we can move that code
into the filter header as well.
So therefore, I'll go to the filter header here
and add the if check
where I check if we have a year
and the available years do not include that year
or if we have a month
and the available months for a year
do not include that month.
And in that case, I still throw an error
and it will bubble up
to the closest error handling component,
so to the closest error JS file.
And therefore, now if we save that and reload,
you see we got two different loading fallbacks here
and it looks like I forgot to rename
one selected year occurrence.
Yep, that should be year, not selected year.
But with that, if we save that and we reload,
we got these two different loading states,
and then we got our data.
And now if I click on that filter again,
you see loading, filter loading use,
and we therefore give the user a better feedback
regarding what's happening behind the scenes.
And of course, you can be as granular as you want to.
You could use one suspense boundary for both components.
So that would also work if you wanted to do that.
This is all up to you as you see here,
but that's the great thing about React and NextJS,
you get a lot of tools and a lot of flexibility,
and now you also know how to use these tools.