Update array object in React Redux reducer

A more general solution, especially if state contains other data besides your posts array:

const posts = (state = null, action) => {
  const post = state.posts.find(p => p.id === action.payload.id);
  switch(action.type) {
    case "PUBLISH_POST":
      return { ...state, posts: [ ...state.posts.filter(p => p !== post), { ...post, status: 1 } ] };
    case "UNPUBLISH_POST":
      return { ...state, posts: [ ...state.posts.filter(p => p !== post), { ...post, status: 0 } ] };
    default:
      return state;
  }
}

Assuming your action is something like:

{
  type: 'UNPUBLISH_POST',
  payload: {
    id: 1,
    user: 'Bob Smith',
    content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vulputate mauris vitae diam euismod convallis. Donec dui est, suscipit at dui vitae, sagittis efficitur turpis. ',
    status: 1
  }
}

Simply use spread operator for it:

const posts = (state = null, action) => {
  switch(action.type){
    case "PUBLISH_POST":
    case "UNPUBLISH_POST":
        const index = this.state.findIndex(post => post.id === action.payload.id)

        return [
           ...state.slice(0, index), // everything before current post
           {
              ...state[index],
              status: action.type === 'PUBLISH_POST' ? 1 : 0,
           },
           ...state.slice(index + 1), // everything after current post
        ]
    default:
        return postList;
  }
}

You can just use the spread operator on your state and it will automatically update it the way you want.

example:

    import { GET_ALL_PENDING_DATAOPS, CHANGE_DATAOPS_ASSIGNED_TO } from "../Actions/types";
const initialState = {
  requests: null
};
export default function(state = initialState, action) {
  const { type, payload } = action;

  switch (type) {
    case GET_ALL_PENDING_DATAOPS:
      return {
        ...state,
        requests: payload
      };
      case CHANGE_DATAOPS_ASSIGNED_TO:          
        return {
          ...state,      
          requests:payload         
        }
    default:
      return state;
  }
}

My CHANGE_DATAOPS_ASSIGNED_TO action maps the previous state, in my axios call i am updating a single request object out of an array of requests, since it is returning a single object, and i am not explicitly returning that as just the state, I am using spread, it updates only that object and leaves the rest alone.


Assuming you have an array of posts, you can search for the ID of the post you want to modify and then update it.

Your initial state:

const initial = {
   posts: [],
}

Your reducer:

case MODIFY_POST:
        return {
            ...state, //Returns the current state
            posts: state.posts.map(post=> post.id === action.id ? // Loop through the array to find the post you want to modify
                { ...post, status: action.status} : post // Copy the post state and then modify it. Else return the same object.
            )
        }

Now, in your actions you can have two actions to toggle the status:

export const enablePost= (post_id) => {
return {
    type: MODIFY_POST,
    id: post_id,
    status: 1
    }
}
export const disablePost= (post_id) => {
return {
    type: MODIFY_POST,
    id: post_id,
    status: 0
    }
}

Tags:

Reactjs

Redux