DEV Community

Cover image for crud in mern stack
Muhammed Shamal PV
Muhammed Shamal PV

Posted on • Edited on

crud in mern stack

Follow me on LinkedIn
Follow me on Github.com

Click & Read

skipping boaring section 😁

recommend for beginners;

1. Setting Up the Backend

mkdir mern-todo-app
cd mern-todo-app
npm init -y

1.2. Install Dependencies

`npm install express mongoose body-parser cors
`
Enter fullscreen mode Exit fullscreen mode

1.3. Set Up the Server
Create an index.js file to set up the Express server and connect to MongoDB.

// index.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cors = require('cors');

const app = express();
const PORT = process.env.PORT || 5000;

mongoose.connect('mongodb://localhost:27017/todoapp', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', () => {
  console.log('Connected to MongoDB');
});

app.use(bodyParser.json());
app.use(cors());

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

Enter fullscreen mode Exit fullscreen mode

1.4. Create Mongoose Models
Create a models directory and define the Todo model.

// models/Todo.js
const mongoose = require('mongoose');

const todoSchema = new mongoose.Schema({
  text: { type: String, required: true },
  completed: { type: Boolean, default: false },
  createdAt: { type: Date, default: Date.now },
});

const Todo = mongoose.model('Todo', todoSchema);

module.exports = Todo;

Enter fullscreen mode Exit fullscreen mode

1.5. Create Routes
Create a routes directory and define the routes for the CRUD operations

// routes/todoRoutes.js
const express = require('express');
const Todo = require('../models/Todo');

const router = express.Router();

// Create a new todo
router.post('/', async (req, res) => {
  try {
    const todo = new Todo({
      text: req.body.text,
    });
    await todo.save();
    res.status(201).json(todo);
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

// Get all todos
router.get('/', async (req, res) => {
  try {
    const todos = await Todo.find();
    res.status(200).json(todos);
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

// Update a todo
router.put('/:id', async (req, res) => {
  try {
    const todo = await Todo.findByIdAndUpdate(req.params.id, req.body, { new: true });
    res.status(200).json(todo);
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

// Delete a todo
router.delete('/:id', async (req, res) => {
  try {
    await Todo.findByIdAndDelete(req.params.id);
    res.status(200).json({ message: 'Todo deleted successfully' });
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

module.exports = router;

Enter fullscreen mode Exit fullscreen mode

Integrate the routes into the index.js file.

// index.js
const todoRoutes = require('./routes/todoRoutes');
app.use('/api/todos', todoRoutes);

2. Setting Up the Frontend

2.1. Initialize the React Project
Create a new React project using Create React App.

npx create-react-app client
cd client

Enter fullscreen mode Exit fullscreen mode

2.2. Install Dependencies
Install Axios for making HTTP requests.

npm install axios

Enter fullscreen mode Exit fullscreen mode

2.3. Create Components
Create a components directory and add the following components: TodoList, TodoItem, and TodoForm.

TodoList Component

// src/components/TodoList.js
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import TodoItem from './TodoItem';
import TodoForm from './TodoForm';

const TodoList = () => {
  const [todos, setTodos] = useState([]);

  useEffect(() => {
    fetchTodos();
  }, []);

  const fetchTodos = async () => {
    const response = await axios.get('http://localhost:5000/api/todos');
    setTodos(response.data);
  };

  const addTodo = async (text) => {
    const response = await axios.post('http://localhost:5000/api/todos', { text });
    setTodos([...todos, response.data]);
  };

  const updateTodo = async (id, updatedTodo) => {
    const response = await axios.put(`http://localhost:5000/api/todos/${id}`, updatedTodo);
    setTodos(todos.map(todo => (todo._id === id ? response.data : todo)));
  };

  const deleteTodo = async (id) => {
    await axios.delete(`http://localhost:5000/api/todos/${id}`);
    setTodos(todos.filter(todo => todo._id !== id));
  };

  return (
    <div>
      <h1>Todo List</h1>
      <TodoForm addTodo={addTodo} />
      {todos.map(todo => (
        <TodoItem
          key={todo._id}
          todo={todo}
          updateTodo={updateTodo}
          deleteTodo={deleteTodo}
        />
      ))}
    </div>
  );
};

export default TodoList;

Enter fullscreen mode Exit fullscreen mode

TodoItem Component

// src/components/TodoItem.js
import React from 'react';

const TodoItem = ({ todo, updateTodo, deleteTodo }) => {
  const toggleComplete = () => {
    updateTodo(todo._id, { ...todo, completed: !todo.completed });
  };

  return (
    <div>
      <input
        type="checkbox"
        checked={todo.completed}
        onChange={toggleComplete}
      />
      <span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
        {todo.text}
      </span>
      <button onClick={() => deleteTodo(todo._id)}>Delete</button>
    </div>
  );
};

export default TodoItem;

Enter fullscreen mode Exit fullscreen mode

TodoFormComponent

// src/components/TodoForm.js
import React, { useState } from 'react';

const TodoForm = ({ addTodo }) => {
  const [text, setText] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    addTodo(text);
    setText('');
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Add a new todo"
      />
      <button type="submit">Add</button>
    </form>
  );
};

export default TodoForm;

Enter fullscreen mode Exit fullscreen mode

2.4. Integrate Components in App
Update the App.js file to include the TodoList component.

// src/App.js
import React from 'react';
import TodoList from './components/TodoList';

function App() {
  return (
    <div className="App">
      <TodoList />
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

2.5. Run the Application
Start the backend server and the React frontend.

`# In the root directory
node index.js

In the client directory

npm start
`

Top comments (22)

Collapse
 
ihssmaheel profile image
Mohamed Ismail • Edited

Liquid syntax error: 'raw' tag was never closed

Collapse
 
muhammedshamal profile image
Muhammed Shamal PV

I'll try to do more better next time

Collapse
 
muhammedshamal profile image
Muhammed Shamal PV

Ya, I'll next time bro

Collapse
 
labeedadar profile image
Labeed Ahmad

Image description any solutions?

Collapse
 
somapti_nahar_2732eafaed6 profile image
Somapti Nahar

use optional channing or null check
{todos?.map(todo => (
key={todo._id}
todo={todo}
updateTodo={updateTodo}
deleteTodo={deleteTodo}
/>
))}

Collapse
 
muhammedshamal profile image
Muhammed Shamal PV

I think you where wrongly type your code!

here the correct :

{todos?.map(todo => (
key={todo._id}
todo={todo}
updateTodo={updateTodo}
deleteTodo={deleteTodo}
/>
))}

Collapse
 
muhammedshamal profile image
Muhammed Shamal PV

use && before using this map.
(for only make mapping if it availble)

eg: let x = [1,2,3,4];

{x && x.map((val,index)=><div>{val}</div>)}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
mateusguedess profile image
Mateus Guedes da Conceição

you can use optional chaining, right?

{x?.map((val,index)=><div>{val}</div>)}

Thread Thread
 
muhammedshamal profile image
Muhammed Shamal PV

again a good option bro

Thread Thread
 
hkara107144 profile image
huseyinkara

Hi,which resource do you recommend to learn mern stack ?

Thread Thread
 
muhammedshamal profile image
Muhammed Shamal PV • Edited

Always recommend using each documentations,

Identify, learn & understands other's codes from git for more.

And bro, always go with yourself taught that will create magic

Collapse
 
benjamin_peikes profile image
Benjamin Peikes

I thought create-react-app was no longer used?

Collapse
 
joel_nada profile image
Joel Nada

It's there but ur choice to use bro, I think you know vite, vite is best to use.

Collapse
 
mohammed_quintel_08e46bc3 profile image
mohammed quintel

it simple, thanks

Collapse
 
muhammedshamal profile image
Muhammed Shamal PV

your welcome bro

Collapse
 
cmanjima profile image
Manjima C

Nice to Learn

Collapse
 
reversetrip profile image
hm hmm

Wow, it's really concise:)

Collapse
 
frank_alimimian_1a2043cb5 profile image
Frank Alimimian

nice explanation

Collapse
 
vsh_torch profile image
Vengatesh TR

Great job. Thanks

Collapse
 
timilehin_abegunde_ec7afd profile image
Timilehin Abegunde

Really helpful for me as a beginner in Backend development

Collapse
 
muhammedshamal profile image
Muhammed Shamal PV

Ya bro

Collapse
 
gitkarasune profile image
Kara Sune

Amazing πŸ‘ but I believe you should go for vite instead of create-react-app