Tengo una aplicación React "simple" que permite a un usuario seleccionar/deseleccionar calendarios para mostrar en un @FullCalendar/React . La aplicación carga una lista de calendarios del servidor, y luego el usuario puede seleccionar o anular la selección de calendarios, y el componente FullCalender debería actualizarse en consecuencia.
A continuación se muestra una versión simplificada de Codesandbox con recuperaciones de servidor simuladas. Notará que se carga correctamente, pero FullCalendar no se actualiza cuando se seleccionan los calendarios. En la consola, puede ver que los datos se actualizan, pero no se vuelven a representar en la pantalla del calendario.
El componente que está causando los problemas es CalendarDisplay . Cuando se vuelve a llamar a render() para actualizar la visualización, no se llama al identificador events={this._fetchEvents} . En cambio, me pregunto si debería usar algo como events={this.state.events} pero luego me encuentro con el problema de saber qué rango de fechas muestra FullCalendar.
/** * Display FullCalendar componenent with events from the selected calendars */ class CalendarDisplay extends Component { constructor(props) { super(props); this.state = { // not used events: [] }; } render() { console.log("Rendering FullCalendar..."); return ( <FullCalendar plugins={[dayGridPlugin]} initialView="dayGridMonth" events={this._fetchEvents} /> ); } _fetchEvents = (info, successCallback, failureCallback) => { // Loop through props.calendars to see which calendars to fetch events for this.props.calendars.forEach((calendar) => { // Fetch events for calendar if "shown" using date range from FullCalendar if (calendar.shown) { let events = fetchEventsFromServer( calendar.id, info.start.valueOf(), info.end.valueOf() ); // Load into FullCalendar successCallback(events); } }); }; }Resulta que la forma de hacerlo es utilizar la API de FullCalendar EventSource y actualizar las fuentes de eventos después de montar o actualizar el componente. Un ejemplo de trabajo se encuentra en CodeSandbox a continuación y el código relevante también se publica a continuación.
class CalendarDisplay extends Component { calendarRef = createRef(); componentDidUpdate(prevProps) { this._fetchEvents(); } componentDidMount() { this._fetchEvents(); } /** * The trick is to render the FulCalendar with no events * and use the EventSource api after the component mounts * or updates */ render() { return ( <FullCalendar ref={this.calendarRef} plugins={[dayGridPlugin]} initialView="dayGridMonth" /> ); } /** * Method to add/remove EventSources when the components props * update (Calendars are selected/unslected) */ _fetchEvents() { // Loop through props.calendars to see which calendars are selected this.props.calendars.forEach((calendar) => { let calendarApi = this.calendarRef.current.getApi(); let eventSource = calendarApi.getEventSourceById(calendar.id); // Remove if present and unselected if (eventSource && !calendar.shown) { console.log("Removing EventSource. CalendarId: " + calendar.id); eventSource.remove(); // Add if selected and not present } else if (calendar.shown && !eventSource) { calendarApi.addEventSource({ id: calendar.id, events: function (info, successCallback, failureCallback) { // Here is where you would place your ajax() call let events = fetchEventsFromServer( calendar.id, info.start.valueOf(), info.end.valueOf() ); // Load into FullCalendar successCallback(events); } }); } }); } }