⏰ Initial Setup for Redux
Step 1: Create reducer
folder and inside index.js
file combine all the reducers
import {combineReducers} from 'redux'
import blogs from './blogs'
const rootReducer = combineReducers({
blogs
});
export default rootReducer;
Step 2: Create a store and using a Provider wrap it around our entire application
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import { createStore, applyMiddleware, compose } from "redux";
import {thunk} from "redux-thunk"
import reducers from "./reducers"
const root = ReactDOM.createRoot(document.getElementById("root"));
//Creates a Redux store by combining reducers, applying middleware
//(in this case, redux-thunk), and composing store enhancers using compose.
const store = createStore(reducers,compose(applyMiddleware(thunk)));
root.render(
<React.StrictMode>
<Provider store={store} >
<App />
</Provider>
</React.StrictMode>
);
Step 3: Starting with our CRUD Operations
A . Fetching all Posts
Step 1: Fetch the api
endpoint
import axios from "axios"
const API = axios.create({baseURL:"http://localhost:8800/"});
export const fetchPosts = () => API.get("/blogs")
Step 2: Create action
using this endpoint
import * as api from "../api";
import { FETCH_BLOGS } from "../constants/actionTypes";
export const getBlogs = () => async (dispatch) => {
try {
const { data } = await api.fetchPosts();
dispatch({ type: FETCH_BLOGS, payload: data });
} catch (error) {
console.log(error);
}
};
Step 3: Create a reducer
for fetching all blogs Operation
import { FETCH_BLOGS } from "../constants/actionTypes";
export default (blogs = [], action) => {
switch (action.type) {
case FETCH_BLOGS:
return action.payload;
break;
default:
return blogs;
}
};
Step 4: Now inside the component
where you want to use this data
import React, { useEffect } from 'react'
import {useDispatch, useSelector} from 'react-redux'
import { getBlogs } from '../actions/blogs';
const Blogs = () => {
const dispatch = useDispatch();
const blogs = useSelector((state)=>state.blogs);
console.log(blogs);
useEffect(()=>{
dispatch(getBlogs());
},[dispatch])
return (
<div>Blogs</div>
)
}
export default Blogs
B. Creating a Blog
Step 1: Fetch the api
endpoint
import axios from "axios"
const API = axios.create({baseURL:"http://localhost:8800/"});
export const createBlog = (newBlog) => API.post("/blogs",newBlog);
Step 2: Create action
for this endpoint
import * as api from "../api";
import { CREATE_BLOG } from "../constants/actionTypes";
export const createBlog = (blog) => async(dispatch) =>{
try {
const {data} = await api.createBlog(blog);
dispatch({type:CREATE_BLOG,payload:data});
} catch (error) {
console.log(error);
}
}
Step 3: Create a reducer
for this Operation
import { CREATE_BLOG} from "../constants/actionTypes";
export default (blogs = [], action) => {
switch (action.type) {
case CREATE_BLOG:
return [...blogs, action.payload];
default:
return blogs;
}
};
Step 4: Inside the Form Component
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { createBlog } from "../actions/blogs";
import {useNavigate} from 'react-router-dom'
const Write = () => {
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const [image, setImage] = useState("");
const navigate = useNavigate();
const dispatch = useDispatch();
const handleCreatePost = async(e) => {
e.preventDefault();
try {
const newBlog = {
title,
content,
image,
};
await dispatch(createBlog(newBlog));
navigate("/");
} catch (error) {
console.log(error);
}
};
return (
<>
<form>
<input
onChange={(e) => setTitle(e.target.value)}
placeholder="Enter your title"
/>
<input
onChange={(e) => setImage(e.target.value)}
placeholder="Enter your image url"
/>
<textarea
onChange={(e) => setContent(e.target.value)}
placeholder="Enter your content"
></textarea>
<button onClick={handleCreatePost} >Create</button>
</form>
</>
);
};
export default Write;
C. Update Blog
Step 1: Fetch the api
endpoint
import axios from "axios"
const API = axios.create({baseURL:"http://localhost:8800/"});
export const fetchBlogByID = (id) => API.get(`/blogs/${id}`);
export const updateBlog = (id,updatedBlog) => API.put(`/blogs/${id}`,updatedBlog)
Step 2: Create actions
for this endpoint
import * as api from "../api";
import {
FETCH_BLOG_ID,
UPDATE_BLOG,
} from "../constants/actionTypes";
export const getBlogByID = (id) => async (dispatch) => {
try {
const { data } = await api.fetchBlogByID(id);
dispatch({ type: FETCH_BLOG_ID, payload: data });
} catch (error) {
console.log(error);
}
};
export const updateBlog = (id, updatedblog) => async (dispatch) => {
try {
const { data } = await api.updateBlog(id, updatedblog);
dispatch({ type: UPDATE_BLOG, payload: data });
} catch (error) {
console.log(error);
}
};
Step 4: Create reducers
for this endpoint
import { FETCH_BLOG_ID, UPDATE_BLOG } from "../constants/actionTypes";
export default (blogs = [], action) => {
switch (action.type) {
case FETCH_BLOG_ID:
return [action.payload];
case UPDATE_BLOG:
blogs.map((blog)=> blog._id === action.payload._id ? action.payload : blog );
break;
default:
return blogs;
}
};
Step 5: Now in the update component
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate, useParams } from 'react-router-dom'
import { getBlogByID, updateBlog } from "../actions/blogs";
const Update = () => {
const { id } = useParams();
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const [image, setImage] = useState("");
const navigate = useNavigate();
const dispatch = useDispatch();
const blog = useSelector((state) => state?.blogs[0]);
useEffect(() => {
dispatch(getBlogByID(id));
}, [dispatch, id]);
useEffect(() => {
if (blog) {
setTitle(blog.title || "");
setImage(blog.image || "");
setContent(blog.content || "");
}
}, [blog]);
const handleUpdate = async (e) => {
e.preventDefault();
const updatedBlog = {
title,
content,
image
};
await dispatch(updateBlog(id, updatedBlog));
navigate("/");
alert("Updated Post")
};
return (
<>
<form>
<input
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Enter your title"
/>
<input
value={image}
onChange={(e) => setImage(e.target.value)}
placeholder="Enter your image url"
/>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="Enter your content"
></textarea>
<button onClick={handleUpdate}>Update</button>
</form>
</>
);
};
export default Update;
D. Delete Blog
Step 1: Fetch the api
endpoint
import axios from "axios"
const API = axios.create({baseURL:"http://localhost:8800/"});
export const deleteBlog = (id) => API.delete(`/blogs/${id}`);
Step 2: Create actions
for this endpoint
import * as api from "../api";
import {
DELETE_BLOG,
} from "../constants/actionTypes";
export const deleteBlog = (id) => async (dispatch) => {
try {
await api.deleteBlog(id);
dispatch({ type: DELETE_BLOG, payload: id });
} catch (error) {
console.log(error);
}
};
Step 3: Create reducer
from the endpoint
import { CREATE_BLOG, DELETE_BLOG, FETCH_BLOGS, FETCH_BLOG_ID, UPDATE_BLOG } from "../constants/actionTypes";
export default (blogs = [], action) => {
switch (action.type) {
case DELETE_BLOG:
return blogs.filter((blog) => blog._id !== action.payload._id);
default:
return blogs;
}
};
Step 4: Now in the component
which contains delete button
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { getBlogs, deleteBlog } from "../actions/blogs";
import { NavLink } from "react-router-dom";
const Blogs = () => {
const dispatch = useDispatch();
const handleDelete = (id) => {
dispatch(deleteBlog(id));
};
return (
<div>
{blogs.map((item, index) => {
return (
<>
<div>
<NavLink to={`/blog/${item._id}`}>
<h1>{item.title}</h1>
</NavLink>
<p>{item.content}</p>
<img src={item.image} />
//creating such kind of function is neccessary or it will be
//deleting all the blogs even if the button is not pressed
<button onClick={() => handleDelete(item._id)}>Delete</button>
</div>
</>
);
})}
</div>
);
};
export default Blogs;