Search code examples
javascriptreactjsmongodbreduxnodes

How to update redux state of arrays?


So I'm creating something like "Trello" clone with react redux nodejs and mongoDB and i have some issue. The problem is when I add a card to a list its not update the redux state, so I will see the card in the list only after a refresh page. (the card added to the DB but not to redux state).

just for more info: boardlists is an array inside the object board from mongo, inside that array there is objects of list, inside each of them there is an array of cards.

here is my code:

REDUCER

const initialState = {
  boardLists: [
    
  ],
};

export default function (state = initialState, action) {
  switch (action.type) {
    case FETCH_ITEMS_BEGIN:
      return {
        ...state,
        loading: true,
        errors: null,
      };
    case FETCH_ITEMS_SUCCESS:
      return {
        ...state,
        loading: false,
        boardLists: action.payload.data.boardLists,
      };
    case FETCH_ITEMS_FAILURE:
      return {
        ...state,
        loading: false,
        errors: action.payload.errors,
        boardLists: [],
      };
    //handless creation of data
    case ADD_LIST:
      return {
        boardLists: [...state.boardLists, action.payload.list],
      };

    case ADD_CARD:
      return {
        boardlists: [...state.boardlists, action.payload.card],
      }

ACTIONS

export const fetchItemsBegin = () => ({
  type: FETCH_ITEMS_BEGIN,
});
export const fetchItemsSuccess = (data) => ({
  type: FETCH_ITEMS_SUCCESS,
  payload: { data },
});
export const fetchItemsFailure = (errors) => ({
  type: FETCH_ITEMS_FAILURE,
  payload: { errors },
});

//dispatched when item needs to be created
export const addList = (list) => {
  return {
    type: ADD_LIST,
    payload: { list },
  };
};

// add card
export const addCard = (card) => {
  return {
    type: ADD_CARD,
    payload: { card }
  };
};

//dispatched when all the lists from board stored in redux store needs to be read
export const getBoardLists = () => {
  return (dispatch) => {
    // function starts
    dispatch(fetchItemsBegin()); // fetching begins
    return http
      .get(`${myUrl}/boards/one`) // req data from server
      .then(({ data }) => {
        console.log(data);

        // if data is found
        dispatch(fetchItemsSuccess(data)); // success
      })
      .catch((error) => dispatch(fetchItemsFailure(error))); //errors
  };
};

COMPONENT THAT HANDLE THE ADD FUNCTION

handleAddCard = () => {
    //add card
    const { text } = this.state;
    const { listID } = this.props;
    const newCard = {
      // _id: uuidv4(),
      text,
    };
    cardService.createCard(newCard, listID);
    this.props.addCard(newCard);
  };

.
.
.
.
.
const mapStateToProps = ({ boardLists, loading, errors }) => ({
  boardLists,
  loading,
  errors,
});

export default connect(mapStateToProps, { addList, addCard, getBoardLists })(ActionButton);

Solution

  • It appears you need to update an object in your lists array, and not add the card item to the list array itself.

    In the actions:

    // add card
    export const addCard = (card, listId) => {
      return {
        type: ADD_CARD,
        payload: { listId, card }
      };
    };
    

    In the Reducer, you will need to find the list with matching id and add the card to its array e.g.:

    case ADD_CARD:
      const {listId, card} = action.payload;
          return {
            ...state,
            boardLists: state.boardLists.map(list => {
              list.cards = list.cards || [];
              return list.id === listId ? {...list, cards: [...list.cards, card]} : list
            }),
          }
    

    This other question on stack overflow could be useful for this part. link