skip to Main Content

I am trying to learn redux and I am facing a problem to push multiple objects into initialState which is an array. I tried the push() method, but this is not working. I get submitter value to my action.payload which is an object.

reducer function:

import { NEWBOOK, DELETEBOOK } from "./actionTypes"

const initialState = [{}]

console.log(typeof(initialState))

const bookingReducer = (state = initialState, action) => {
  switch (action.type) {
    case NEWBOOK:
      return {
        ...state,
        stae: action.payload,
      }

    case DELETEBOOK:
      return { ...state }

    default:
      return { state }
  }
}

export default bookingReducer

dispatch data:

const booked = useSelector((state) => state);
const dispatch = useDispatch();

const newBookDisp = (value) => {
  dispatch(newBook(value));
}

console.log(booked);
const [inputData, setInputData] = useState([]);
const handleOnChange = e => {
  const field = e.target.name;
    const value = e.target.value;
    const newInputData = { ...inputData };
    newInputData[field] = value;
    setInputData(newInputData);
}
  
const submitBook = (e) => {
  e.preventDefault();
  console.log('clicked on submit button.')
  const from = inputData.from;
  const to = inputData.to;
  const date = inputData.date;
  const ticketclassName = inputData.ticketclassName;
  const guests = inputData.guests;
  const id = parseInt(booked.state.length) + 1;

  const allData = { from, to, date, ticketclassName, guests, id }  
}

2

Answers


  1. If the book state is an array the initial state should probably be an empty array. You can then shallow copy the array and append the new data to it.

    When you want to delete a book, e.g. remove from the array, use Array.prototype.filter to remove the specific element(s).

    Also, the default case should just return the current/existing state as-is and not create a new object reference. This way it won’t unnecessarily trigger any component rerenders if it wasn’t updated.

    const initialState = [];
    
    const bookingReducer = (state = initialState, action) => {
      switch (action.type) {
        case NEWBOOK:
          return state.concat(action.payload);
          // or
          return [...state, action.payload];
    
        case DELETEBOOK:
          return state.filter(/* filter condition callback */);
    
        default:
          return state;
      }
    }
    

    Running Demo

    Edit redux-can-not-push-an-object-into-an-array

    If you really want to use Array.prototype.push then it would done similar to this:

    case NEWBOOK:
      const newState = state.slice(); // shallow copy
      newState.push(action.payload);  // update copy
      return newState;                // return copy
    

    This is because the push method mutates the array it operates over.

    Login or Signup to reply.
  2. Running example:

    Find on codesandbox

    It is more understandable when keeping the state variable as object since we can add/append/delete multiple keys in future.

    You can use array as state as well, not much drawback in it, but it will have impact outside the reducer as well. Following encapsulation mechanism, that would be wrong.

    import { act } from "react-dom/test-utils";
    import { NEWBOOK, DELETEBOOK } from "./actionTypes";
    
    const initialState = { myBookings: [] };
    
    console.log(typeof initialState);
    const bookingReducer = (state = initialState, action) => {
      switch (action.type) {
        case NEWBOOK:
          return {
            ...state,
            myBookings: (state?.myBookings ?? []).concat(action.payload)
          };
        default:
          return state;
      }
    };
    
    export default bookingReducer;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search