Next.js is a popular React framework that enables efficient server-side rendering and seamless client-side navigation. This makes it easier to build high-performance and SEO-friendly web applications.
In this answer, we will build a basic to-do list in Next.js. Here's a step-by-step guide for this:
Follow these steps to set up a new Next.js project:
Next.js is a framework built on top of Node.js, so it is required to have Node.js installed on the machine.
Create a new directory for the Next.js project. Do this by opening the terminal or command prompt and running the following command:
mkdir next-application
Navigate into the newly created directory using the following command:
cd next-application
Then, run the following command in the command prompt or terminal to create a new Next.js project:
npx create-next-app todo-app
Now we can run the project by simply using the npm run dev
command.
Here are the steps to create a basic to-do list:
import { useState } from 'react';export default function Home() {const [task, setTask] = useState('');const [tasksArray, setTasksArray] = useState([]);// ...}
export default function Home() {// ...const inputChange = (e) => {setTask(e.target.value);};// ...}
export default function Home() {// ...const inputSubmit = (e) => {e.preventDefault();if (task.trim()) {setTasksArray([...tasksArray, task]);setTask('');}};// ...}
export default function Home() {// ...const handleDelete = (index) => {setTasksArray(tasksArray.filter((_, i) => i !== index));};// ...}
export default function Home() {// ...return (<div><h1> To-do List in Next.js </h1><form onSubmit={inputSubmit}><input type="text" value={task} onChange={inputChange} placeholder="Enter a task" /><button type="submit">Add task</button></form><ul>{tasksArray.map((task, index) => (<li key={index}>{task}<button onClick={() => handleDelete(index)}>Delete</button></li>))}</ul></div>);}
Click the "Run" button to execute the to-do list coding example.
import { useState } from 'react'; export default function Home() { const [task, setTask] = useState(''); const [tasksArray, setTasksArray] = useState([]); const inputChange = (e) => { setTask(e.target.value); }; const inputSubmit = (e) => { e.preventDefault(); if (task.trim()) { setTasksArray([...tasksArray, task]); setTask(''); } }; const handleDelete = (index) => { setTasksArray(tasksArray.filter((_, i) => i !== index)); }; return ( <div> <h1> To-do List in Next.js </h1> <form onSubmit={inputSubmit}> <input type="text" value={task} onChange={inputChange} placeholder="Enter a task" /> <button type="submit">Add task</button> </form> <ul> {tasksArray.map((task, index) => ( <li key={index}> {task} <button onClick={() => handleDelete(index)}>Delete</button> </li> ))} </ul> </div> ); }
The code above can be divided into the following parts:
Lines 1–5: In this part, we import the useState
hook from React and initialize two state variables: task
to track the current task being entered, and tasksArray
to store the list of tasks.
Lines 7–9: Then, we define the inputChange
function that will be called whenever the input field value changes. It updates the task
state with the current value of the input field.
Lines 11–17: In this section, we define the inputSubmit
function, which is used to handle form submissions. The behavior of the default form submission is prevented, and if the task is not empty, it is checked to see if it is added to the tasksArray
state array. In addition, an empty string is used to reset the task
state.
Lines 19–21: In this section, we define the handleDelete
method, which deletes a task based on its index from the tasksArray
state array. It makes a new array using the filter
function that doesn't include the job at the given index.
Lines 25–29: The user interface is rendered by this last section. There is a header, an input area, and a submit button on the form. The inputChange
function changes the input field's value, which is connected to the task
state.
Lines 30–37: A list of tasks is generated by mapping the tasksArray
state array, with each task presented as a list item. There is a "Delete" button next to each task, which runs the handleDelete
method with the task's index.
Another method to build a to-do list is by using context API that integrates the context-based state management into a Next.js application:
// context/TodoContext.js import React, { createContext, useContext, useReducer } from 'react'; // Create a context for the to-do list state const TodoContext = createContext(); // Define initial state and reducer function const initialState = { todos: [], }; const todoReducer = (state, action) => { switch (action.type) { case 'ADD_TODO': return { ...state, todos: [...state.todos, action.payload], }; case 'DELETE_TODO': return { ...state, todos: state.todos.filter(todo => todo.id !== action.payload), }; default: return state; } }; // Define a provider component export const TodoProvider = ({ children }) => { const [state, dispatch] = useReducer(todoReducer, initialState); return ( <TodoContext.Provider value={{ state, dispatch }}> {children} </TodoContext.Provider> ); }; // Custom hook to consume the context export const useTodoContext = () => useContext(TodoContext);
In this step, we're wrapping our Next.js app with the TodoProvider
to make the to-do list state available to all components.
import { TodoProvider } from './context/todo'; function MyApp({ Component, pageProps }) { return ( <TodoProvider> <Component {...pageProps} /> </TodoProvider> ); } export default MyApp;
In this step, we're using the useTodoContext
hook to access the to-do list state and dispatch actions to update it.
// pages/index.js import { useState } from 'react'; import { useTodoContext } from './context/todo'; export default function Home() { const [task, setTask] = useState(''); const { state, dispatch } = useTodoContext(); const inputChange = (e) => { setTask(e.target.value); }; const inputSubmit = (e) => { e.preventDefault(); if (task.trim()) { const newTodo = { id: Date.now(), text: task, completed: false, }; dispatch({ type: 'ADD_TODO', payload: newTodo }); setTask(''); } }; const handleDelete = (id) => { dispatch({ type: 'DELETE_TODO', payload: id }); }; return ( <div> <h1> To-do List in Next.js </h1> <form onSubmit={inputSubmit}> <input type="text" value={task} onChange={inputChange} placeholder="Enter a task" /> <button type="submit">Add task</button> </form> <ul> {state.todos.map(todo => ( <li key={todo.id}> {todo.text} <button onClick={() => handleDelete(todo.id)}>Delete</button> </li> ))} </ul> </div> ); }
Components can access the state and dispatch actions to update it, resulting in a simpler and more maintainable state management solution for our Next.js application.
See the complete executable application below:
// pages/_app.js import { TodoProvider } from './context/todo.js'; function MyApp({ Component, pageProps }) { return ( <TodoProvider> <Component {...pageProps} /> </TodoProvider> ); } export default MyApp;
Note: The basic code is similar to the application provided above.