ERROR Function components cannot have string refs. We recommend using useRef() instead. Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref at coerceRef (http://localhost:3000/static/js/bundle.js:59386:21) at createChild (http://localhost:3000/static/js/bundle.js:59620:32) at reconcileChildrenArray
This a React Calendar Application that should handle full CRUD operation with localforage to have a persist data upon refresh.
I cannot do my CRUD Operation as the Details Modal is not showing up upon click anywhere in the Calendar or even on the existing event.
my CalendarInfo.js
import React, { useState, useEffect, useRef } from "react";
import moment from "moment";
import { Calendar, momentLocalizer, Views } from "react-big-calendar";
import "react-big-calendar/lib/css/react-big-calendar.css";
// import { GetInitialEvents } from "../reducer";
import Details from "./Details";
import localForage from "localforage";
import { useStateValue } from "../StateProvider";
const localizer = momentLocalizer(moment);
let allViews = Object.keys(Views).map((k) => Views[k]);
console.log(allViews, "MISSION");
const CalendarInfo = () => {
const [{ allEvents }, dispatch] = useStateValue();
const [showModal, setShowModal] = useState(false);
const [eventType, setEventType] = useState("add");
const [newIndex, setNewIndex] = useState(0);
const [eventInfo, setEventInfo] = useState({});
useEffect(() => {
var allEvents = [
{
id: 0,
title: "Hello!",
allDay: true,
start: new Date(moment()),
end: new Date(moment()),
hexColor: "black",
notes: "Have a great day!",
},
];
localForage.getItem("AllEvents", function (err, allEve) {
if (allEve) {
allEvents = allEve;
} else {
localForage.setItem("AllEvents", allEvents);
}
});
dispatch({ type: "ALL_EVENTS", allEvents });
}, [dispatch]);
const handleHide = () => {
setShowModal(false);
};
const handleShow = (slotInfo, type) => {
const currentIndex = allEvents.length;
setShowModal(true);
setEventType(type);
setEventInfo(slotInfo);
setNewIndex(currentIndex);
};
const deleteEvent = (id) => {
dispatch({
type: "REMOVE_EVENT",
payload: id,
});
setShowModal(false);
};
const addEvent = (obj) => {
dispatch({
type: "ADD_EVENT",
payload: obj,
});
setShowModal(false);
};
const updateEvent = (obj) => {
dispatch({
type: "UPDATE_EVENT",
payload: {
id: obj.id,
obj: obj,
},
});
setShowModal(false);
};
const eventStyle = (event, start, end, isSelected) => {
const bgColor = event.hexColor ? event.hexColor : "#265985";
const style = {
backgroundColor: bgColor,
borderRadius: "5px",
opacity: 1,
color: "white",
border: "0px",
display: "block",
};
return {
style: style,
};
};
return (
<div className="bodyContainer">
<div className="well well-sm">
<h3 className="instruction">Instructions</h3>
<strong>To add an event: </strong> Click on the day you want to add an
event or drag up to the day you want to add the event for multiple day
event! <br />
<strong>To update and delete an event:</strong> Click on the event you
wish to update or delete!
</div>
<Details
modalShow={showModal}
handleHide={handleHide}
eventType={eventType}
eventInfo={eventInfo}
newIndex={newIndex}
deleteEvent={deleteEvent}
addEvent={addEvent}
updateEvent={updateEvent}
/>
<Calendar
localizer={localizer}
selectable
events={allEvents}
views={allViews}
step={60}
showMultiDayTimes
defaultDate={new Date(moment())}
onSelectEvent={(event) => handleShow(event, "edit")}
onSelectSlot={(slotInfo) => handleShow(slotInfo, "add")}
style={{ minHeight: "500px" }}
eventPropGetter={eventStyle}
/>
</div>
);
};
export default CalendarInfo;
my Details.js
import React, { useState, useEffect } from "react";
import { Modal, Button } from "react-bootstrap";
import moment from "moment";
import Datetime from "react-datetime";
import "../css/datetime.css";
// var Datetime = require('react-datetime');
const Details = ({
modalShow,
handleHide,
eventType,
eventInfo,
newIndex,
deleteEvent,
addEvent,
updateEvent,
}) => {
const [showModal, setShowModal] = useState(modalShow);
const [eventDetail, setEventDetail] = useState({
id: eventType === "add" ? newIndex : eventInfo.id,
title: eventInfo && eventInfo.title ? eventInfo.title : "",
start: new Date(eventInfo && eventInfo.start ? eventInfo.start : moment()),
end: new Date(eventInfo && eventInfo.end ? eventInfo.end : moment()),
allDay: eventInfo.allDay ? true : false,
hexColor: "#265985",
notes: eventInfo.notes ? eventInfo.notes : "",
});
useEffect(() => {
setShowModal(modalShow);
setEventDetail({
id: eventType === "add" ? newIndex : eventInfo.id,
title: eventInfo && eventInfo.title ? eventInfo.title : "",
start: new Date(
eventInfo && eventInfo.start ? eventInfo.start : moment()
),
end: new Date(eventInfo && eventInfo.end ? eventInfo.end : moment()),
allDay: eventInfo.allDay ? true : false,
hexColor: eventInfo.hexColor ? eventInfo.hexColor : "#265985",
notes: eventInfo.notes ? eventInfo.notes : "",
});
}, [eventInfo, eventType, modalShow, newIndex]);
const changeHandler = (e, ref) => {
var eventDetail = eventDetail;
let val = "";
if (ref !== "allDay") {
if (ref === "start" || ref === "end") {
val = new Date(moment(e));
} else {
val = e.target.value;
}
} else {
val = e.target.checked;
}
eventDetail[ref] = val;
setEventDetail(eventDetail);
};
return (
<Modal show={showModal} onHide={handleHide}>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title">Event Details</Modal.Title>
</Modal.Header>
<Modal.Body>
<label> Event Name </label>
<input
type="text"
className="form-control"
placeholder="Enter the Event Name"
ref="title"
value={eventDetail.title}
onChange={(e) => changeHandler(e, "title")}
/>
<label> Start Date </label>
{eventDetail.allDay ? (
<Datetime
value={eventDetail.start}
dateFormat="MM-DD-YYYY"
timeFormat={false}
onChange={(e) => changeHandler(e, "start")}
/>
) : (
<Datetime
value={eventDetail.start}
onChange={(e) => changeHandler(e, "start")}
/>
)}
<label> End Date </label>
{eventDetail.allDay ? (
<Datetime
value={eventDetail.end}
dateFormat="MM-DD-YYYY"
timeFormat={false}
onChange={(e) => changeHandler(e, "end")}
/>
) : (
<Datetime
value={eventDetail.end}
onChange={(e) => changeHandler(e, "end")}
/>
)}
<label> Event Notes </label>
<textarea
className="form-control"
placeholder="Event Notes"
ref="notes"
value={eventDetail.notes}
onChange={(e) => changeHandler(e, "notes")}
/>
<label> Event Color </label>
<input
type="color"
value={eventDetail.hexColor}
onChange={(e) => changeHandler(e, "hexColor")}
style={{ marginRight: "20px", marginLeft: "5px" }}
/>
<input
type="checkBox"
name="all_Day"
value={eventDetail.id}
checked={eventDetail.allDay}
onChange={(e) => changeHandler(e, "allDay")}
/>
<label> All Day </label>
</Modal.Body>
<Modal.Footer>
{eventType === "add" ? (
<Button bsStyle="success" onClick={() => addEvent(eventDetail)}>
Add
</Button>
) : (
<Button bsStyle="warning" onClick={() => updateEvent(eventDetail)}>
Update
</Button>
)}
{eventType === "add" ? null : (
<Button bsStyle="danger" onClick={() => deleteEvent(eventDetail.id)}>
Delete
</Button>
)}
<Button onClick={handleHide}>Close</Button>
</Modal.Footer>
</Modal>
);
};
export default Details;
my reducer.js
// import moment from "moment";
import localForage from "localforage";
export const initialState = {
allEvents: [],
};
const reducer = (state = initialState, action = {}) => {
switch (action.type) {
case "ALL_EVENTS":
return { ...state, allEvents: action.allEvents };
case "REMOVE_EVENT":
var newState = state;
newState.allEvents = newState.allEvents.filter(function (obj) {
return obj.id !== action.payload;
});
localForage.setItem("AllEvents", newState.allEvents);
return newState;
case "ADD_EVENT":
var newState2 = state;
newState2.allEvents.push(action.payload);
localForage.setItem("AllEvents", newState2.allEvents);
return newState2;
case "UPDATE_EVENT":
var newState3 = state;
newState3.allEvents[action.payload.id] = action.payload.obj;
localForage.setItem("AllEvents", newState3.allEvents);
return newState3;
default:
return state;
}
};
export default reducer;
I was expecting to add, update or delete an Event, but the Details model is not working, and not even giving an error!
The
Detailscomponent is using invalid Reactrefprop values, specificallyref="title"on theinputelement andref="notes"on thetextareaelement.These should both be removed.
localForage.getItemis asynchronous and theuseEffectcallback inCalendarInfodoesn't wait for it to fetch stored data before it dispatches the"ALL_EVENTS"action to "initialize" theallEventsstate value.Update the effect to only dispatch the
"ALL_EVENTS"action once the stored state has been retrieved.