react useState and setState claims calendarList.push is not a function

Viewed 104

New to React. I'm trying to keep a state which tracks an array of calendar events. I set the state equal to some dummyData and if a new calendar event was passed in to the UserEvents(props) then I want to add it to the calendarList state.

It's giving an error that calendarList.push() is not a function. When I console.log it, it is an array so I don't understand why I can't use the push() method on it.

import React, { useEffect, useState } from 'react';
import Countdown from '../countdown/Countdown';

function UserEvents(props){
    let dummyData = [
        {name: "birthday", date: '03/20/2021'},
        {name: "christmas", date: '12/25/2020'},
        {name: "thanksgiving", date: '11/26/2020'}
      ]
    
    const [calendarList, setCalendarList] = useState(dummyData);
  
    if(props.calendarItem){
        setCalendarList(calendarList.push( props.calendarItem ));
    }

    return (
        <div className="App">
          {
            calendarList.map((item, index) => {
              return(
                <Countdown name={item.name} date={item.date}></Countdown>
              )  
            })
          }
        </div> 
      )
}

export default UserEvents; 

If you console.log(calendarList)

If you console.log(calendarList) is shows its an object but also prints "4". It does this twice as you can see and I'm unsure why as well.

1 Answers

.push has 2 problems:

  • It returns the new length of the array, so
setCalendarList(calendarList.push( props.calendarItem ));

will do something like setCalendarList(4)

  • It mutates the existing array (never mutate state in React)

You're also calling setCalendarList unconditionally every render.

Change it so that the initial state includes the calendarItem:

const [calendarList, setCalendarList] = useState([
  ...dummyData,
  ...(props.calendarItem ? [props.calendarItem] : [])
]);

(see Add elements inside Array conditionally in JavaScript)

You could also use your original code, but instead of the if, use the effect hook:

useEffect(() => {
  if (props.calendarItem) {
    setCalendarList([
      ...calendarList,
      props.calendarItem
    ]);
  }
}, []);
Related