I’m trying to learn redux-toolkit with a project.
I’m using “toEditPostId” variable (initial value is null) inside the store to get the id of the post I want to edit, the app works fine when I set its value to an id string, but when I click the clear button in my form component which calls the “dispatch(setToEditPostId(null))”, then the entire app re-renders and “handleSubmit” function is automatically called and that then adds a new empty post, which I don’t want to happen.
I have added “****************” near the snippets which are causing problem.
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axiosInstance from "../utils/axiosInstance";
export const fetchMemoryPosts = createAsyncThunk('posts/fetchPosts', async (_, thunkApi)=>{
try {
const response = await axiosInstance.get('/posts');
return response.data.posts;
} catch (error) {
const errorMessage = error.response.data.match(/Error: (.*?)<br>/)[1];
const errorCode = error.response.status;
return thunkApi.rejectWithValue({errorMessage,errorCode});
}
});
export const createMemoryPost = createAsyncThunk('posts/createPosts', async(data, thunkApi)=>{
const tagsArr = data.tags.split(',').map((ele)=> ele.trim());
const preparedData = {...data, tags: tagsArr};
try {
const response = await axiosInstance.post('/posts/create', preparedData);
return response.data.data;
} catch (error) {
const errorMessage = error.response.data.match(/Error: (.*?)<br>/)[1];
const errorCode = error.response.status
return thunkApi.rejectWithValue({errorMessage, errorCode})
}
})
const initialState = {
posts: [],
status: 'idle',
error: null,
toEditPostId: null, //The state variable to track the id of the post to edit*************
}
const postsSlice = createSlice({
name: 'posts',
initialState,
reducers: { // changing the value to an id and back to null here***********************
setToEditPostId(state,action){
state.toEditPostId = action.payload;
}
},
extraReducers(builder){
builder
.addCase(fetchMemoryPosts.pending, (state,_)=>{
state.status = 'loading';
})
.addCase(fetchMemoryPosts.fulfilled, (state, action)=>{
state.status = 'success';
state.posts = action.payload;
})
.addCase(fetchMemoryPosts.rejected, (state, action)=>{
state.status = 'failure';
state.error = action.payload;
})
.addCase(createMemoryPost.fulfilled, (state, action)=>{
state.status = 'success';
state.posts = state.posts.concat(action.payload);
})
.addCase(createMemoryPost.rejected, (state, action)=>{
state.status = 'failure';
state.error = action.payload;
})
}
});
export const getAllPostsSelector = (state) => state.posts.posts;
export const getPostsErrorSelector = (state) => state.posts.error;
export const getPostsStatusSelector = (state) => state.posts.status;
export const getToEditPostIdSelector = (state) => state.posts.toEditPostId;
export const { setToEditPostId } = postsSlice.actions;
export default postsSlice.reducer;
Below is the Form component.
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createMemoryPost, setToEditPostId, getToEditPostIdSelector, getAllPostsSelector } from '../../features/postsSlice';
const Form = () => {
const dispatch = useDispatch();
const allPosts = useSelector(getAllPostsSelector);
const postId = useSelector(getToEditPostIdSelector);
let targetPost;
if(postId){
targetPost = allPosts.filter((post) => post._id === postId);
}
console.log("pi->", postId)
console.log("po->", targetPost);
const initialPostDataState = {
creator: '', title: '', message:'', tags:''
}
const [postData, setPostData] = useState(initialPostDataState);
// Below function runs unnecessarily when the dispatch(setToEditPostId(null)) is called*********************************
const handleSubmit =(e)=>{
console.log("it ran");
e.preventDefault()
dispatch(createMemoryPost(postData));
setPostData(initialPostDataState);
}
const handleInput =(e)=>{
setPostData({...postData, [e.target.name]: e.target.value})
}
const clearForm = ()=>{
dispatch(setToEditPostId(null))
setPostData(initialPostDataState);
}
return (
<main className='bg-transparent_bg w-full flex'>
<form className='w-full text-center space-y-3 p-2 box-border'
onSubmit={handleSubmit}
>
<h3
className='font-extrabold '
>
{postId !== null? "" : "Create a memory"}
</h3>
<input
className='input'
type="text"
placeholder='Creator'
name='creator'
value={postData.creator}
onChange={handleInput}
/>
<input
className='input'
type="text"
placeholder='Title'
name='title'
value={postData.title}
onChange={handleInput}
/>
<textarea
className='input'
placeholder='Message'
name="message"
cols="30"
rows="5"
value={postData.message}
onChange={handleInput}
/>
<input
className='input'
type="text"
placeholder='Tags (coma seperated)'
name='tags'
value={postData.tags}
onChange={handleInput}
/>
<div className='flex justify-around py-1 box-border'>
<button
type='submit'
className='bg-blue-400 w-24'
>
Submit
</button>
<button // clear button to call dispatch to set value to null *********************
onClick={()=>dispatch(setToEditPostId(null))}
className='bg-red-500 w-24'
>
Clear
</button>
</div>
</form>
</main>
)
}
export default Form;