Bill Sambrone
Bill Sambrone

Reputation: 4454

React Big Calendar (w/Typescript) not showing events

I'm trying to use React Big Calendar with typescript. After reading the docs, I am able to get the calendar itself to display (setting height very important!), however I cannot get any events to show up. I am seeing that the array of events I have is populating correctly, and this is code I took from the examples and made it TS friendly and also for useState. From reading other answers, I also made sure to check the accessors but it didn't have an impact whether it was defined or not.

For anything Typescript related that I did, the source for it is here: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-big-calendar/react-big-calendar-tests.tsx

Here is how I display my component:

import React from 'react';
import moment from 'moment'
import { momentLocalizer } from 'react-big-calendar';
import 'react-big-calendar/lib/css/react-big-calendar.css';
import SelectableCalendar from './SelectableCalendar';

const localizer = momentLocalizer(moment);

export default function Availability() {

    return (
      <div style={{ height: "100vh" }}>
        <SelectableCalendar localizer={localizer} />
      </div>
    );
  }

Here is my component itself:

import React, { useState } from 'react'
import { Calendar, View, DateLocalizer } from 'react-big-calendar'
import moment from 'moment';

const allViews: View[] = ['agenda', 'day', 'week', 'month'];

interface Props {
    localizer: DateLocalizer;
}

class CalendarEvent {
    title: string;
    allDay: boolean;
    start: Date;
    end: Date;
    desc: string;
    resourceId?: string;
    tooltip?: string;

    constructor(_title: string, _start: Date, _endDate: Date, _allDay?: boolean, _desc?: string, _resourceId?: string) {
        this.title = _title;
        this.allDay = _allDay || false;
        this.start = _start;
        this.end = _endDate;
        this.desc = _desc || '';
        this.resourceId = _resourceId;
    }
  }


export default function SelectableCalendar ({ localizer }: Props) {
    const [events, setEvents] = useState([] as CalendarEvent[]);

    const handleSelect = ({ start, end }) => {
        const title = window.prompt('New Event name')

        if (title) {
            let newEvent = {} as CalendarEvent;
            newEvent.start = moment(start).toDate();
            newEvent.end = moment(end).toDate();
            newEvent.title = title;

            events.push(newEvent)
            setEvents(events)
        }
      }

    return (
      <>
        <div>
          <strong>
            Click an event to see more info, or drag the mouse over the calendar
            to select a date/time range.
          </strong>
        </div>
        <Calendar
          selectable
          localizer={localizer}
          events={events}
          defaultView='month'
          views={allViews}
          defaultDate={new Date(2020, 4, 21)}
          onSelectEvent={event => alert(event.title)}
          onSelectSlot={handleSelect}
          startAccessor='start'
          endAccessor='end'
          titleAccessor='title'
        />
      </>
    )
  }

What am I missing?

Upvotes: 1

Views: 5192

Answers (1)

The issue is that you are mutating your state and then setting it. React doesn't recognize a change (since you already made it to the state directly) and therefore doesn't re-render the component.

This can be fixed by setting the new state directly with the changes, i.e.:

    if (title) {
        let newEvent = {} as CalendarEvent;
        newEvent.start = moment(start).toDate();
        newEvent.end = moment(end).toDate();
        newEvent.title = title;

        // Erroneous code:
        //     events.push(newEvent)
        //     setEvents(events)
        setEvents([
          ...events,
          newEvent
        ])
    }

Here is a playground with your code and the above fix that shows this is working: https://codesandbox.io/s/currying-bush-2c3hc?file=/src/App.tsx

Upvotes: 4

Related Questions