I'm learning redux, and i've a method addPosts
to add posts to the list of posts, and I'm doing it like this.
import { createSlice } from "@reduxjs/toolkit";
var initialState = [{ number: 1 }, { number: 2 }, { number: 3 }, { number: 4 }];
export const postsSlice = createSlice({
name: "postsSlice",
initialState,
reducers: {
addPost: (state, action) => {
state = [...state, action.payload];
},
},
});
export const allPosts = (state) => state.posts;
export const { addPost } = postsSlice.actions;
export default postsSlice.reducer;
and using the state like this.
import { useSelector, useDispatch } from "react-redux";
import { addPost, allPosts } from "./postsSlice";
function Posts() {
var posts = useSelector(allPosts);
var dispatch = useDispatch();
return (
<div>
{posts.map((post) => (
<div>{post.number}</div>
))}
{/* add post */}
<button
onClick={() => {
dispatch(addPost({ number: 1 }));
console.log(posts);
}}
>
addpost
</button>
</div>
);
}
export default Posts;
using state.push(action.payload)
works somehow, altough the documentation says not use update state like this, and update in an immutable way.
like this state = [...state, action.payload]
. it does not update state with this immutable way.
I don't know what is wrong that i'm doing. thanks in advance for any help
CodePudding user response:
You are misreading the wrong documentation for the wrong tool it seems - in a Redux Toolkit createSlice
reducer, it is always 100% correct to use something like state.push
to mutably modify the object in the state
variable.
What you cannot do however is what you are trying here: reassign the state
variable. That had never any effect in any kind of Redux reducer, unless you would return that state
variable later.
If you want to do that, you will need to return [...state, action.payload]
instead and leave the state
variable alone altogether - it should not be reassigned.
But the recommended way would be that push.
For more, please read Writing Reducers with Immer
CodePudding user response:
As per this instead of directly changing into state
you can return in this way
return [...state, action.payload]
Depending on your definition of initialState
Please have a look into working example of react-redux-toolkit-slice-example
Below is the definition of slice
import { createSlice } from "@reduxjs/toolkit";
const initialState = [{ number: 1 }];
export const postsSlice = createSlice({
name: "postsSlice",
initialState,
reducers: {
addPost: (state, action) => {
return [...state, action.payload];
}
}
});
export const allPosts = (state) => state.posts || [];
export const { addPost } = postsSlice.actions;
export default postsSlice.reducer;
Defining the reducer(postSlice) in store
import { configureStore } from "@reduxjs/toolkit";
import postsReducer from "../features/posts/postsSlice";
export default configureStore({
reducer: {
posts: postsReducer
}
});
Use of slice in component
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { addPost, allPosts } from "./postsSlice";
const Posts = () => {
var posts = useSelector(allPosts);
var dispatch = useDispatch();
return (
<div>
{posts.map((post, key) => (
<div key={key}>{post.number}</div>
))}
{/* add post */}
<button
onClick={() => {
dispatch(
addPost({
number: Math.max(...posts.map(({ number }) => number)) 1
})
);
console.log(posts);
}}
>
Add Post
</button>
</div>
);
};
export default Posts;