I am trying to update an array within the stories array in my state. I want the payload object to come to the top of the stories array containing it. I tried the method below but it keeps on adding the payload multiple times to the array.
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { StoriesService } from "../../services/stories.service";
export const createStory = createAsyncThunk(
"stories/createStory",
async (arg, thunkAPI) => {
const data = JSON.stringify(arg);
try {
await StoriesService.createStory(data);
return thunkAPI.fulfillWithValue({ msg: "Story upload successful" });
} catch (error) {
if (error.response.status === 413) {
return thunkAPI.rejectWithValue({ msg: "Upload size too large!" });
}
if (error.response.data.errors) {
const data = error.response.data.errors[0];
return thunkAPI.rejectWithValue(data);
}
return thunkAPI.rejectWithValue({
msg: "An error occured. Please try again",
});
}
}
);
export const deleteStory = createAsyncThunk(
"stories/deleteStory",
async (arg, thunkAPI) => {
try {
await StoriesService.deleteStory(arg);
thunkAPI.dispatch(getLoggedInUserStories);
return thunkAPI.fulfillWithValue({ msg: "Story deleted successfully" });
} catch (error) {
return thunkAPI.rejectWithValue({
msg: "An error occured while deleting story",
});
}
}
);
export const getLoggedInUserStories = createAsyncThunk(
"stories/getLoggedInUserStories",
async (arg, thunkAPI) => {
try {
const response = await StoriesService.getLoggedInUserStories(
thunkAPI.signal
);
return response.data;
} catch (error) {
return thunkAPI.rejectWithValue({
msg: "An error occured.",
});
}
}
);
export const getFeedStories = createAsyncThunk(
"stories/getFeedStories",
async (arg, thunkAPI) => {
try {
const response = await StoriesService.getFeedStories(thunkAPI.signal);
return response.data;
} catch (error) {
return thunkAPI.rejectWithValue({
msg: "An error occured.",
});
}
}
);
const initialState = {
isUploadingStory: false,
isDeletingStory: false,
userStories: [],
stories: [],
showStoryCreateModal: false,
};
const storiesSlice = createSlice({
name: "stories",
initialState,
reducers: {
clearStories(state, _) {
return initialState;
},
toggleStoryCreateModal(state, _) {
state.showStoryCreateModal = !state.showStoryCreateModal;
},
updateStories(state, { payload }) {
if (state.stories.length > 0) {
for (let i=0; i < state.stories.length; i++) {
const story = state.stories[i];
const filterededStoryArray = story.filter(item => item.author === payload.author);
if (filterededStoryArray.length > 0) {
filterededStoryArray.push(payload);
}
state.stories[i] = filterededStoryArray;
break;
}
} else {
state.stories = state.stories.unshift(...[payload]);
}
},
},
extraReducers: (builder) => {
builder.addCase(createStory.pending, (state, action) => {
state.isUploadingStory = true;
});
builder.addCase(createStory.fulfilled, (state, action) => {
state.isUploadingStory = false;
});
builder.addCase(createStory.rejected, (state, action) => {
state.isUploadingStory = false;
});
builder.addCase(getLoggedInUserStories.fulfilled, (state, action) => {
let stories =
action.payload.data.length > 0 ? [...action.payload.data] : [];
state.userStories = stories;
});
builder.addCase(getLoggedInUserStories.rejected, (state, action) => {});
builder.addCase(getFeedStories.fulfilled, (state, action) => {
let stories = action.payload.data.filter(
(userStory) => userStory.length > 0
);
state.stories = stories;
});
builder.addCase(deleteStory.pending, (state, action) => {
state.isDeletingStory = true;
});
builder.addCase(deleteStory.fulfilled, (state, action) => {
state.isDeletingStory = false;
});
builder.addCase(deleteStory.rejected, (state, action) => {
state.isDeletingStory = false;
});
},
});
export const selectStoryUploading = (state) => state.stories.isUploadingStory;
export const selectUserStories = (state) => state.stories.userStories;
export const selectFeedStories = (state) => state.stories.stories;
export const selectIsDeletingStory = (state) => state.stories.isDeletingStory;
export const selectShowStoryCreateModal = (state) =>
state.stories.showStoryCreateModal;
export const { clearStories, toggleStoryCreateModal, updateStories } = storiesSlice.actions;
export default storiesSlice.reducer;
The updateStories function is where I am having a challenge. Please what is the best way to go about this? The data I use to update this state comes from a web socket. The useEffect handles the updating of the state with the updateStory function.
useEffect(() => {
postSocket.connect();
storySocket.connect();
postSocket.on("post update", (data) => {
setNewPostLoading(true);
setTimeout(() => {
setNewPostLoading(false);
},1000);
setTimeout(() => {
dispatch(addPostToFeed(JSON.parse(data)));
},1000);
});
postSocket.on("single post update", data => {
dispatch(updatePostFeed(JSON.parse(data)));
});
storySocket.on("new story", data => {
console.log(data);
dispatch(updateStories(JSON.parse(data)));
});
postSocket.on("delete post", data => {
dispatch(removePostFromFeed(JSON.parse(data)));
});
},[dispatch, posts]);
I need to update the stories array in the state but the method I tried above is not working.
I was able to solve the challenge by making the change below to my code. Thank you
updateStories(state, { payload }) {
const newArray = [];
if (state.stories.length > 0) {
for (let i=0; i < state.stories.length; i++) {
const story = state.stories[i];
const filteredStoryArray = story.filter(item => item.author === payload.author);
if (filteredStoryArray.length > 0) {
state.stories = state.stories.filter((story, index) => index !== i);
newArray.push(...story);
}
break;
}
}
if (newArray.filter(item => item._id === payload._id).length === 0) {
newArray.push(payload)
};
state.stories.push(newArray);
},
},
Thank you Linda for your support.