如何在 react-big-calendar 中显示动态事件?
How to display dynamic events in react-big-calendar?
我已经使用 react-big-calendar 来显示动态事件,我的 api url 就像“api/user/events/year/month/”,我必须在其中提供当前观看年份和月份获取事件的编号。我已经使用 onNavigate 和 onView 来更新当前日期和日历的当前视图。我得到了正确的可见范围,但在提供月数和年份时,没有传递正确的月数。
显示事件的日历组件:
import React, { useEffect, useState } from 'react'
import { Calendar, momentLocalizer } from 'react-big-calendar'
import moment from "moment";
import "react-big-calendar/lib/css/react-big-calendar.css"
import * as dates from "../../utils/EMDates"
import { Card, CardContent, Paper, Typography, SvgIcon, CardActions, Button } from '@material-ui/core';
import EMCustomToolbar from "./EMCustomToolbar"
import { useSelector, useDispatch } from "react-redux";
import IconButton from '@material-ui/core/IconButton';
import CardHeader from '@material-ui/core/CardHeader';
import Dialog from '@material-ui/core/Dialog';
import { SHOW_EVENT_DETAILS } from '../../redux/constants/UserPlatform/EMEventsConstant';
import { useNavigate } from 'react-router';
import { EMDoGetMonthEventsAction } from '../../redux/actions/UserPlatform/Events';
const ColoredDateCellWrapper = ({ children }) =>
React.cloneElement(React.Children.only(children), {
style: {
backgroundColor: 'lightblue',
},
})
function eventStyleGetter (event) {
var backgroundColor = '#' + event.hexColor;
var style = {
backgroundColor: backgroundColor,
borderRadius: '12px',
color: 'black',
border: '0px',
display: 'block'
};
if (event.isMine){
style.backgroundColor = "lightgreen"
}
return {
style: style
};
}
const localizer = momentLocalizer(moment);
function EMCalendar({data, ...props}) {
const [open, setOpen] = useState(false);
const [selectedevent, setSelectedEvent] = useState({})
const dispatch = useDispatch()
const navigate = useNavigate()
const [currentDate, setCurrentDate] = useState(new Date())
const [currentView, setCurrentView] = useState("month")
const userData = useSelector((state)=> state.auth || {})
const [calendarView, setCalendarView] = React.useState({})
const [displayedDateRange, setdisplayedDateRange] = React.useState({})
function tConvert (time) {
// Check correct time format and split into components
time = time.toString ().match (/^([01]\d|2[0-3])(:)([0-5]\d)(:[0-5]\d)?$/) || [time];
if (time.length > 1) {
time = time.slice (1);
time[5] = +time[0] < 12 ? 'AM' : 'PM';
time[0] = +time[0] % 12 || 12;
}
return time.join ('');
}
let setCurrentDate1 = async (date) => {
await computeDisplayedDateRange();
setCurrentDate(date);
}
let setCurrentView1 = async (view) => {
await computeDisplayedDateRange();
setCurrentView(view)
}
let computeDisplayedDateRange = () => {
setCalendarView({year: currentDate.getFullYear(),
month: currentDate.getMonth()})
let start = moment(currentDate).startOf(currentView);
let end = moment(currentDate).endOf(currentView);
if(currentView == 'month') {
start = start.startOf('week');
end = end.endOf('week');
}
setdisplayedDateRange({start:start.toString(), end:end.toString()})
dispatch(EMDoGetMonthEventsAction({userData, calendarView:calendarView}))
}
useEffect(() => {
computeDisplayedDateRange()
}, [currentDate, currentView])
const monthNames = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN",
"JUL", "AUG", "SEPT", "OCT", "NOV", "DEC"
];
return(
<div>
<div>Displayed Date Rage: {displayedDateRange.start} - {displayedDateRange.end}</div>
<Paper elevation={4}>
<Calendar
onNavigate={setCurrentDate1}
onView={setCurrentView1}
localizer={localizer}
events={data}
// views={views}
style={{ height: 750 }}
showMultiDayTimes
max={dates.add(dates.endOf(new Date(), 'day'), -1, 'hours')}
// defaultDate={new Date()}
date={currentDate}
view={currentView}
startAccessor="start"
endAccessor="end"
components={{
timeSlotWrapper: ColoredDateCellWrapper,
toolbar : EMCustomToolbar
}}
eventPropGetter={eventStyleGetter}
onSelectEvent = {(event) => {
setOpen(true);
setSelectedEvent(event)
}}
/>
</Paper>
<Dialog
open={open}
onClose={() => {setOpen(false)}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
maxWidth="xs"
>
<div style={{position:"absolute", top:0, right:0}}>
<IconButton onClick={() => {setOpen(false)}} color="secondary">
<DeleteIcon />
</IconButton>
</div>
<Card>
<div style={{display:"flex"}}>
<CardHeader
style={{maxWidth:"70%"}}
title={selectedevent && selectedevent.title}
subheader={<>
<Typography>{selectedevent.event_start_time && tConvert(selectedevent.event_start_time)} {" "}-{" "}
{selectedevent.event_end_time && tConvert(selectedevent.event_end_time)}
</Typography>
<Typography color="textPrimary" style={{fontWeight:"bolder",}}>{selectedevent && selectedevent.event_location}</Typography>
</>}
/>
<div style={{margin:"auto", textAlign:"center"}}>
<Typography component="h6" variant="h6" style={{fontWeight:"bolder"}}>
{selectedevent.start && selectedevent.start.getDate()}
</Typography>
<Typography component="h6" variant="h6" style={{fontWeight:"bolder"}}>{selectedevent.start && monthNames[selectedevent.start.getMonth()]}</Typography>
</div>
</div>
<CardContent>
<Typography>
{selectedevent && selectedevent.postText}
</Typography>
</CardContent>
</Card>
<CardActions style={{justifyContent: 'center', marginBottom:'2%'}}>
<Button variant="contained" style={{backgroundColor: "#3399ff"}}
onClick={() => {
dispatch({
type:SHOW_EVENT_DETAILS,
payload:{
route:selectedevent.route,
eventId:selectedevent.id,
value:true
},
})
if(selectedevent.route === "eventsByMe" || "allMyEvents"){
navigate("/users/events/yourevents")
} else {
navigate("/users/events/searchevents")
}
}}>
View Details
</Button>
</CardActions>
</Dialog>
</div>
)
}
export default EMCalendar;
function DeleteIcon(props) {
return (
<SvgIcon {...props}>
<path d="M11.436,3.375A8.061,8.061,0,1,0,19.5,11.436,8.06,8.06,0,0,0,11.436,3.375Zm2.042,10.979-2.042-2.042L9.394,14.354a.619.619,0,1,1-.876-.876l2.042-2.042L8.518,9.394a.619.619,0,0,1,.876-.876l2.042,2.042,2.042-2.042a.619.619,0,1,1,.876.876l-2.042,2.042,2.042,2.042a.622.622,0,0,1,0,.876A.615.615,0,0,1,13.478,14.354Z" />
</SvgIcon>
);
}
我想你的减速器和你当地的状态之间存在竞争条件。首先,尽可能使用 moment
。其次,使用函数局部变量以相同的值更新 reducer 中的状态和本地状态。只是一个猜测。您可能还想将此 computeDisplayedDateRange()
包装在 useCallback
中,以便 知道 您正在使用当前的 currentDate
和 currentView
值。
let computeDisplayedDateRange = () => {
const thisDate = moment(currentDate)
const newCalView = {
year: thisDate.year(),
month: thisDate.month()
};
setCalendarView(newCalView);
// wrap `thisDate` in a new moment, as moment is mutable
const start = moment(thisDate).startOf(currentView);
const end = moment(thisDate).endOf(currentView);
if(currentView == 'month') {
start = start.startOf('week');
end = end.endOf('week');
}
setdisplayedDateRange({
start: start.toDate().toString(),
end: end.toDate().toString()
});
dispatch(EMDoGetMonthEventsAction({
userData,
calendarView: newCalView
}));
}
我已经使用 react-big-calendar 来显示动态事件,我的 api url 就像“api/user/events/year/month/”,我必须在其中提供当前观看年份和月份获取事件的编号。我已经使用 onNavigate 和 onView 来更新当前日期和日历的当前视图。我得到了正确的可见范围,但在提供月数和年份时,没有传递正确的月数。
显示事件的日历组件:
import React, { useEffect, useState } from 'react'
import { Calendar, momentLocalizer } from 'react-big-calendar'
import moment from "moment";
import "react-big-calendar/lib/css/react-big-calendar.css"
import * as dates from "../../utils/EMDates"
import { Card, CardContent, Paper, Typography, SvgIcon, CardActions, Button } from '@material-ui/core';
import EMCustomToolbar from "./EMCustomToolbar"
import { useSelector, useDispatch } from "react-redux";
import IconButton from '@material-ui/core/IconButton';
import CardHeader from '@material-ui/core/CardHeader';
import Dialog from '@material-ui/core/Dialog';
import { SHOW_EVENT_DETAILS } from '../../redux/constants/UserPlatform/EMEventsConstant';
import { useNavigate } from 'react-router';
import { EMDoGetMonthEventsAction } from '../../redux/actions/UserPlatform/Events';
const ColoredDateCellWrapper = ({ children }) =>
React.cloneElement(React.Children.only(children), {
style: {
backgroundColor: 'lightblue',
},
})
function eventStyleGetter (event) {
var backgroundColor = '#' + event.hexColor;
var style = {
backgroundColor: backgroundColor,
borderRadius: '12px',
color: 'black',
border: '0px',
display: 'block'
};
if (event.isMine){
style.backgroundColor = "lightgreen"
}
return {
style: style
};
}
const localizer = momentLocalizer(moment);
function EMCalendar({data, ...props}) {
const [open, setOpen] = useState(false);
const [selectedevent, setSelectedEvent] = useState({})
const dispatch = useDispatch()
const navigate = useNavigate()
const [currentDate, setCurrentDate] = useState(new Date())
const [currentView, setCurrentView] = useState("month")
const userData = useSelector((state)=> state.auth || {})
const [calendarView, setCalendarView] = React.useState({})
const [displayedDateRange, setdisplayedDateRange] = React.useState({})
function tConvert (time) {
// Check correct time format and split into components
time = time.toString ().match (/^([01]\d|2[0-3])(:)([0-5]\d)(:[0-5]\d)?$/) || [time];
if (time.length > 1) {
time = time.slice (1);
time[5] = +time[0] < 12 ? 'AM' : 'PM';
time[0] = +time[0] % 12 || 12;
}
return time.join ('');
}
let setCurrentDate1 = async (date) => {
await computeDisplayedDateRange();
setCurrentDate(date);
}
let setCurrentView1 = async (view) => {
await computeDisplayedDateRange();
setCurrentView(view)
}
let computeDisplayedDateRange = () => {
setCalendarView({year: currentDate.getFullYear(),
month: currentDate.getMonth()})
let start = moment(currentDate).startOf(currentView);
let end = moment(currentDate).endOf(currentView);
if(currentView == 'month') {
start = start.startOf('week');
end = end.endOf('week');
}
setdisplayedDateRange({start:start.toString(), end:end.toString()})
dispatch(EMDoGetMonthEventsAction({userData, calendarView:calendarView}))
}
useEffect(() => {
computeDisplayedDateRange()
}, [currentDate, currentView])
const monthNames = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN",
"JUL", "AUG", "SEPT", "OCT", "NOV", "DEC"
];
return(
<div>
<div>Displayed Date Rage: {displayedDateRange.start} - {displayedDateRange.end}</div>
<Paper elevation={4}>
<Calendar
onNavigate={setCurrentDate1}
onView={setCurrentView1}
localizer={localizer}
events={data}
// views={views}
style={{ height: 750 }}
showMultiDayTimes
max={dates.add(dates.endOf(new Date(), 'day'), -1, 'hours')}
// defaultDate={new Date()}
date={currentDate}
view={currentView}
startAccessor="start"
endAccessor="end"
components={{
timeSlotWrapper: ColoredDateCellWrapper,
toolbar : EMCustomToolbar
}}
eventPropGetter={eventStyleGetter}
onSelectEvent = {(event) => {
setOpen(true);
setSelectedEvent(event)
}}
/>
</Paper>
<Dialog
open={open}
onClose={() => {setOpen(false)}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
maxWidth="xs"
>
<div style={{position:"absolute", top:0, right:0}}>
<IconButton onClick={() => {setOpen(false)}} color="secondary">
<DeleteIcon />
</IconButton>
</div>
<Card>
<div style={{display:"flex"}}>
<CardHeader
style={{maxWidth:"70%"}}
title={selectedevent && selectedevent.title}
subheader={<>
<Typography>{selectedevent.event_start_time && tConvert(selectedevent.event_start_time)} {" "}-{" "}
{selectedevent.event_end_time && tConvert(selectedevent.event_end_time)}
</Typography>
<Typography color="textPrimary" style={{fontWeight:"bolder",}}>{selectedevent && selectedevent.event_location}</Typography>
</>}
/>
<div style={{margin:"auto", textAlign:"center"}}>
<Typography component="h6" variant="h6" style={{fontWeight:"bolder"}}>
{selectedevent.start && selectedevent.start.getDate()}
</Typography>
<Typography component="h6" variant="h6" style={{fontWeight:"bolder"}}>{selectedevent.start && monthNames[selectedevent.start.getMonth()]}</Typography>
</div>
</div>
<CardContent>
<Typography>
{selectedevent && selectedevent.postText}
</Typography>
</CardContent>
</Card>
<CardActions style={{justifyContent: 'center', marginBottom:'2%'}}>
<Button variant="contained" style={{backgroundColor: "#3399ff"}}
onClick={() => {
dispatch({
type:SHOW_EVENT_DETAILS,
payload:{
route:selectedevent.route,
eventId:selectedevent.id,
value:true
},
})
if(selectedevent.route === "eventsByMe" || "allMyEvents"){
navigate("/users/events/yourevents")
} else {
navigate("/users/events/searchevents")
}
}}>
View Details
</Button>
</CardActions>
</Dialog>
</div>
)
}
export default EMCalendar;
function DeleteIcon(props) {
return (
<SvgIcon {...props}>
<path d="M11.436,3.375A8.061,8.061,0,1,0,19.5,11.436,8.06,8.06,0,0,0,11.436,3.375Zm2.042,10.979-2.042-2.042L9.394,14.354a.619.619,0,1,1-.876-.876l2.042-2.042L8.518,9.394a.619.619,0,0,1,.876-.876l2.042,2.042,2.042-2.042a.619.619,0,1,1,.876.876l-2.042,2.042,2.042,2.042a.622.622,0,0,1,0,.876A.615.615,0,0,1,13.478,14.354Z" />
</SvgIcon>
);
}
我想你的减速器和你当地的状态之间存在竞争条件。首先,尽可能使用 moment
。其次,使用函数局部变量以相同的值更新 reducer 中的状态和本地状态。只是一个猜测。您可能还想将此 computeDisplayedDateRange()
包装在 useCallback
中,以便 知道 您正在使用当前的 currentDate
和 currentView
值。
let computeDisplayedDateRange = () => {
const thisDate = moment(currentDate)
const newCalView = {
year: thisDate.year(),
month: thisDate.month()
};
setCalendarView(newCalView);
// wrap `thisDate` in a new moment, as moment is mutable
const start = moment(thisDate).startOf(currentView);
const end = moment(thisDate).endOf(currentView);
if(currentView == 'month') {
start = start.startOf('week');
end = end.endOf('week');
}
setdisplayedDateRange({
start: start.toDate().toString(),
end: end.toDate().toString()
});
dispatch(EMDoGetMonthEventsAction({
userData,
calendarView: newCalView
}));
}