My intention from the get-go was to create two buttons that'll let you navigate to the next or previous article from this article that you're reading now.
I was ecstatic as I had already established a miniature pattern and formulated the steps I'll embark on with the flowchart in my head. "How hard could it be?". And for the first time — Yes, how hard could it be, really? Little did I know that I'll encounter some obstacles as I progress. I'll save that for later.
One goal I had in mind while building this was to make it as simple as possible. No need to "over-engineer" and ruin it all.
A good side-effect
Realizing the cause of this error, relieved me.
My intention again, was to let you go directly to the next article on my blog, I realized that after adding this tiny detail, the logic behind how the articles on my blog are rendered made the buttons more dynamic.
Normally, when you scroll to the bottom of this article, you should see two UI elements serving as buttons, pointing to the next article or a previous one. But, that's not the case here;
Since I am mutating the array of articles on my blog by rendering a featured article — normally again, the featured article on most blogs are the latest ones.
But here, it is different, the featured one is a random article from the array of articles on the blog.
When the featured post is identified, it is removed from the posts array by filtering its id
property like so:
This alone alters the order of the articles in the array. Hence the post controllers that let you navigate to another article are generated randomly.
Establishing a mental model
Realizing the cause of this error as I said previously, relieved me. At least, now, I know where to go from there.id previously, "How hard could this be?".
I figured out that Since I have a function that returns all the articles for me, I can get the index of the current article, increment its index when I click on the next button, and decrement it when I want to read the previous article and that's all.
But then, I ran into a build issue in production. Locally with localhost:3000
everything worked fine — another wake-up call to always run the build script before pushing to prod. Here's the error below;
If you take a look at the image above, you'll see that there's a prerendering error for the "/blog/year-in-review-2022" and "/blog/building-a-nextjs-preloader-the-right-way" articles. This particular issue got me wondering for several hours, what the cause could be.
After yelling endlessly at my PC and asking JavaScript kept tormenting me, I found out that the reason why the title
properties on both articles were undefined is that getAllArticles()
— the helper function I mentioned previously — returns all the mdx files in alphabetical order, like so:
And in a reversed manner, the last item in the articles folder — year-in-review-2022.mdx — receives the first index value, zero (0).
So, when you go to either of the links, say, the first one for example, and you click on the prev button, you're performing this operation 0 - 1
, which in turn becomes -1
.
There's no article in the array with a negative index. Hence the reason I got the "cannot read property of undefined (reading title)" error.
The same thing happens with the last item in the array. Incrementing its value will result in a new index that does not exist.
Finding a workaround
The first step I took was to look for a way to sort the list of articles based on the date they were published so that the order is proper.
I went on to assign the slug
variable to a new one — currentPost
, got the index of the last article by subtracting 1
from its length, and found the index of the current article with the indexOf()
method.
These modifications, however, did not fix the error though. I still had to look for a way to conditionally render the values assigned to the nextIndex
and prevIndex
variables that I already created.
Remember how I explained the arithmetic process behind the last and first index issues? I realized that, to calculate the nextIndex
I need to check if the currentIndex
is the lastIndex
. If it is I return the current index as a value, if not, I increment the value.
For the prevIndex
the logic remains the same. But, this time, I'm comparing the currentIndex
with 0
and I decrement if it does not meet the condition.
The next thing on my list was to get the title and slug of each article respectively by assigning them to the values of the indexes I already obtained.
You may have wondered why there have been little to no variable declarations in the snippets I've been sharing. Well, you can have a look at them now in this getStaticProps()
method.
The snippet above is what my approach looked like. I'm using the let
keyword, so I can re-assign these variables along the way and be able to pass them as props on the page.
Rendering a UI
Now that I have the slug and title variables in the controllers
object, I can use them in the current article's UI like so:
And that's it — again.
Let me know if you have any questions by tweeting at me here: @kafLamed