Part 17: Refactoring getStaticProps for Better Code Organization in Next.js
[Pages] Loading Data

In our previous discussion, we learned how to load data from a local file within the getStaticProps function in a Next.js application. Now, we'll take a step further by refactoring our code to follow the "separation of concerns" principle. This involves extracting specific logic into separate modules, resulting in cleaner and more maintainable code.
Why Refactor?
Refactoring helps in organizing code better, making it easier to manage and understand. By separating concerns, we ensure that each part of our codebase has a distinct responsibility, leading to fewer bugs and simpler changes in the future.
Step-by-Step Refactoring Process
Extract Logic into a Function
First, we'll encapsulate the logic for reading post data into a dedicated function within our existing file. Let's call this function
getPost:// pages/posts/first-post.js import Head from 'next/head'; import { getPost } from '../../lib/posts'; export async function getStaticProps() { console.log('[FirstPostPage] getStaticProps()'); const post = await getPost('first-post'); return { props: { post }, }; } function FirstPostPage({ post }) { console.log('[FirstPostPage] render:', post); return ( <> <Head> <title>{`${post.title} - My Blog`}</title> </Head> <main> <h1>{post.title}</h1> <p>{post.body}</p> </main> </> ); } export default FirstPostPage;Generalize the Function
We can make our
getPostfunction more flexible by allowing it to accept a "slug" parameter. This parameter will determine which post to load, based on the URL part that identifies a specific post.// lib/posts.js import { readFile } from 'fs/promises'; export async function getPost(slug) { const data = await readFile(`content/posts/${slug}.json`, 'utf8'); return JSON.parse(data); }Move Logic to a Separate Module
Since the logic for fetching post data isn't directly related to rendering the page, it's beneficial to move this logic to a separate module. A common practice in Next.js is to create a
libfolder for such utility functions.Create a file named
posts.jsinside thelibdirectory:// lib/posts.js import { readFile } from 'fs/promises'; export async function getPost(slug) { const data = await readFile(`content/posts/${slug}.json`, 'utf8'); return JSON.parse(data); }
Update Imports and Test
After moving the function, ensure you import it correctly in your page component and test the application to confirm everything works as expected:
// pages/posts/first-post.js import Head from 'next/head'; import { getPost } from '../../lib/posts'; export async function getStaticProps() { console.log('[FirstPostPage] getStaticProps()'); const post = await getPost('first-post'); return { props: { post }, }; }If you encounter any errors, verify that all necessary imports (like
readFile) are present in the new module.
Conclusion
Through refactoring, we've organized our codebase by separating concerns, which enhances maintainability and clarity. By moving data-fetching logic to a dedicated module, we ensure that page components focus solely on rendering content. This approach not only aligns with best practices but also prepares our codebase for future scalability and flexibility. As you continue developing your Next.js application, consider how similar refactoring techniques can be applied to further improve code quality.
Last updated