Is there way to set DayPickerRangeController custom visible month after component rendered?
I have 'handleMonthChange' function which I want to change visible month when this function is called. I try to set 'initialVisible' month but it is not working.
import { useState } from "react";
import moment from "moment";
import { DayPickerRangeController } from "react-dates";
import "react-dates/initialize";
import "react-dates/lib/css/_datepicker.css";
const Date = (props) => {
const [startDate, setStartDate] = useState(null);
const [endDate, setEndDate] = useState(null);
const [focusedInput, setFocusedInput] = useState("startDate");
const [initialMonth, setInitialMonth] = useState(moment("01-01-2021"));
const handleDatesChange = ({ startDate, endDate }) => {
setStartDate(moment(startDate, "MMM DD, YYYY"));
setEndDate(moment(endDate, "MMM DD, YYYY"));
};
const handleMonthChange = () => {
console.log("month change");
setInitialMonth(moment("01-06-2021"));
};
return (
<div>
<DayPickerRangeController
onDatesChange={handleDatesChange}
focusedInput={focusedInput}
startDate={startDate}
endDate={endDate}
numberOfMonths={2}
initialVisibleMonth={() => initialMonth}
/>
<button onClick={handleMonthChange}>Change Visible Month</button>
</div>
);
};
export default Date;
I found workaround solution. Unmounting component and then render with new initialMonth
import { useState } from "react";
import moment from "moment";
import { DayPickerRangeController } from "react-dates";
import "react-dates/initialize";
import "react-dates/lib/css/_datepicker.css";
const Date = (props) => {
const [startDate, setStartDate] = useState(null);
const [endDate, setEndDate] = useState(null);
const [focusedInput, setFocusedInput] = useState("startDate");
const [initialMonth, setInitialMonth] = useState(moment("01-01-2021"));
const handleDatesChange = ({ startDate, endDate }) => {
setStartDate(moment(startDate, "MMM DD, YYYY"));
setEndDate(moment(endDate, "MMM DD, YYYY"));
};
const handleMonthChange = () => {
setInitialMonth(null)
setTimeout(() => setInitialMonth(moment("01-06-2021")), 0);
};
if(!initialMonth) return <div>Loading...</div>
return (
<div>
<DayPickerRangeController
onDatesChange={handleDatesChange}
focusedInput={focusedInput}
startDate={startDate}
endDate={endDate}
numberOfMonths={2}
initialVisibleMonth={() => initialMonth}
/>
<button onClick={handleMonthChange}>Change Visible Month</button>
</div>
);
};
export default Date;
Related
I'm making an interactive graph which re-renders when you select a different date. It used to re-render fine before I made some fundamental changes (moved state responsibilites to the components instead of app.js. When I change the date, it does seem to actually change the url in the component responsible for making the api call. However, it's not re-rendering even though it's in a useEffect, and it did re-render before.
I'm new to React so it might be something very obvious. I'm also not sure if this is the right way to do things so I'm open for any pointers to improve my application or best practices.
App.js: Preferably I'd remove the useGetData and useURLSwitcher in the app.js, but without them it's not able to load the url on start up.
import "./App.css";
import React, { useEffect, useState } from "react";
import { Button } from "./components/button/Button";
import useGetData from "./apiData/useGetData";
import BarChart from "./components/BarChart";
import { SpinnerDiamond } from "spinners-react";
import GraphChart from "./components/GraphChart";
import { DatePicker } from "./components/datePicker/DatePicker";
import useURLSwitcher from "./apiData/useURLSwitcher";
import { DatePickerWithButton } from "./components/datePickerWithButton/DatePickerWithButton";
const App = () => {
const {url} = useURLSwitcher()
const { dataNew, isLoading, error } = useGetData(url);
console.log(url)
return isLoading ? (
<div className="spinner">
<SpinnerDiamond
size={400}
speed={100}
secondaryColor="#354A54"
color={"#00BAEC"}
/>
</div>
) : error ? (
console.log(error)
) : (
<div className="app">
<div className="example">
<div className="graph-box">
<div id="wrapper">
<GraphChart graphData={dataNew} />
</div>
<div className="side-bar">
<DatePicker
nameOne={"Start Date"}
nameTwo={"End Date"}
/>
<Button name={"Apply"}/>
</div>
</div>
<div className="graph-box">
<div id="wrapper">
<BarChart graphData={dataNew} />
</div>
<div className="side-bar">
<DatePickerWithButton
nameOne={"Start Date"}
nameTwo={"End Date"}
name={"Apply"}
/>
</div>
</div>
DatePickerWithButton: These used to be two separate components which I combined to make it easier to set the start,- and end dates.
import React, { useState } from "react";
import "./DatePickerWithButton.css";
import useURLSwitcher from "../../apiData/useURLSwitcher";
import useGetData from "../../apiData/useGetData";
import { format, parseISO } from "date-fns";
export const DatePickerWithButton = ({
nameOne,
nameTwo,
name,
}) => {
let tempStartDate ="";
let tempEndDate= "";
const [startDate, setStartDate] = useState();
const [endDate, setEndDate] = useState();
const {url} = useURLSwitcher(startDate, endDate)
const onClick = () => {
setStartDate(tempStartDate);
setEndDate(tempEndDate);
}
return (
<>
<div className="date-box">
<label className="styleDate">{nameOne}</label>
<input
className="datePicker"
type="date"
onChange={(e) => tempStartDate = e.target.value}
></input>
</div>
<div className="date-box">
<label className="styleDate">{nameTwo}</label>
<input
className="datePicker"
type="date"
onChange={(e) => tempEndDate= e.target.value}
></input>
</div>
<button className="button-28" onClick={()=> onClick()}>
{name}
</button>
{console.log("start date " + startDate, " end date "+ endDate)}
</>
);
};
The custom hook I made to fetch the data:
import { useState, useEffect } from "react";
import axios from "axios";
const config = {
"Content-Type": "application/json",
Accept: "application/json",
};
const useGetData = (url) => {
const [dataNew, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(async () => {
const { data } = await axios({
url: url,
method: "GET",
data: null,
withCredentials: true,
headers: config,
}).catch((err) => setError(err));
console.log(url)
const newData = data.value.map((d) => {
const personId = d._personId;
const startDate =
d._startDate;
const endDate =
d._endDate;
return {
personId,
startDate,
endDate,
};
});
setData(newData);
setIsLoading(false);
}, [url]);
return {
dataNew,
isLoading,
error,
};
};
export default useGetData;
The second custom hook that should set the right url once selected with the DatePickerWithButton. Links have been pruned:
import { format, parseISO } from "date-fns";
import { isEmpty } from "lodash";
import useGetData from "./useGetData";
const useURLSwitcher = (setStartDate, setEndDate) => {
const startDate = setStartDate;
const endDate = setEndDate;
console.log(setStartDate);
console.log(setEndDate);
let url = "";
const RawThisYear = new Date();
const RawLastYear = new Date();
RawLastYear.setFullYear(RawLastYear.getFullYear() - 5);
const ThisYear = format(RawThisYear, "yyyy-dd-MM");
const LastYear = format(RawLastYear, "yyyy-dd-MM");
if (startDate === undefined && endDate === undefined) {
url = `http://192.168/{LastYear} lt ${ThisYear}`;
} else {
// if (startDate > endDate) {
// alert("Start date can't be greater than the end date!");
// } else {
if (startDate !== undefined && endDate !== undefined) {
url = `http://192.168/$filter={startDate}{endDate}`;
console.log(url)
}
}
console.log(url)
return {
url,
};
};
export default useURLSwitcher;
In general a component will re-render if its state or incoming props changes. The App.js is also a component.
At first glance, when you change a date in DatePickerWithButton, it does not seems updating any state/props that the parent App.js is aware of, hence no re-rendering.
The useURLSwitcher() just returns an object with url string.
The onClick function below only updates the DatePickerWithButton's local states.
const [startDate, setStartDate] = useState();
const [endDate, setEndDate] = useState();
const {url} = useURLSwitcher(startDate, endDate)
const onClick = () => {
setStartDate(tempStartDate);
setEndDate(tempEndDate);
}
The GraphChart component is a child component of App.js, but no state/props changes in App.js, hence, GraphChart does not re-render when only the DatePickerWithButton's local states changes.
This component displays calendar to the patients so that they can select the appointment day from the appointment days of doctor. Doctor appointment days are fetched from api. What i am trying to achieve is to disable all other weekdays days in the calendar except the doctor appointment days so that patients can only press one of the appointment days. i am using react-native-calendars library and date-fns-library for dates. However my app is freezing once while loop is being defined. What am i doing wrong here ? Also is there a better way of doing what i am trying to achieve?
import { View } from "react-native";
import React, { useEffect, useState } from "react";
import { Calendar, CalendarProps } from "react-native-calendars";
import startOfMonth from "date-fns/startOfMonth";
import endOfMonth from "date-fns/endOfMonth";
import isBefore from "date-fns/isBefore";
import addDays from "date-fns/addDays";
import format from "date-fns/format";
import setDay from "date-fns/setDay";
import api from "../../config/api";
import Layout from "../UI/Layout";
import RegularText from "../UI/Text/RegularText";
import { useAppSelector } from "../../store/hooks";
import { useRoute } from "#react-navigation/native";
import { AppointmentDaysScreenRouteProp } from "../../#types/navigation";
const weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] as const;
type weekday = typeof weekdays[number];
const CalendarComponent = () => {
const language = useAppSelector((state) => state.language.selected);
const [markedDates, setMarkedDates] = useState<CalendarProps["markedDates"]>(
{}
);
const [disabledledWeekdays, setDisbaledWeekdays] = useState<number[]>([]);
const route = useRoute<AppointmentDaysScreenRouteProp>();
const { doctorId } = route.params;
const [loading, setLoading] = useState(true);
let text = {
loading: "...Please wait",
};
if (language === "اردو") {
text = {
loading: "...لوڈ ہو رہا ہے",
};
}
useEffect(() => {
(async () => {
try {
const res = await api.get<{ appointmentDays: weekday[] }>(
`/appointments/appointmentDays/doctorId/${doctorId}`
);
const { appointmentDays } = res.data;
const disabledDays = weekdays
.filter((item) => !appointmentDays.includes(item))
.map((item) => weekdays.indexOf(item));
const now = new Date();
getDisabledDays(now.getMonth(), now.getFullYear(), disabledDays);
setDisbaledWeekdays(disabledDays);
} finally {
setLoading(false);
}
})();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const getDisabledDays = (
month: number,
year: number,
daysIndexes: number[]
) => {
const now = new Date();
now.setFullYear(year, month);
const pivot = startOfMonth(now);
const end = endOfMonth(now);
const dates: CalendarProps["markedDates"] = {};
const disabled = { disabled: true, disableTouchEvent: true };
//THIS WHILE LOOP IS FREEZING MY APP
//IF I REMOVE THIS LOOP APP WORKS FINE
while (isBefore(pivot, end)) {
daysIndexes.forEach((day) => {
const copy = setDay(new Date(pivot), day);
dates[format(copy, "yyyy-MM-dd")] = disabled;
});
addDays(pivot, 7);
}
setMarkedDates(dates);
return dates;
};
return (
<Layout>
<View>
{loading ? (
<RegularText>{text.loading}</RegularText>
) : (
<Calendar
theme={{
textSectionTitleDisabledColor: "#d9e1e8",
}}
markedDates={markedDates}
onDayPress={(day) => {
console.log("dosomething with ", day);
}}
firstDay={1}
enableSwipeMonths={true}
disabledDaysIndexes={disabledledWeekdays}
onMonthChange={(date) => {
getDisabledDays(date.month - 1, date.year, disabledledWeekdays);
}}
/>
)}
</View>
</Layout>
);
};
export default CalendarComponent;
Looking at the documentation, I'm it seems that addDays(date, amount) is returning a new date and not modifying the value of pivot. Try doing pivot = addDays(pivot, 7)
I'm trying to render components with a loop. What I did was to use array.map inside a JSX return block of the function component. The component is to render each individual dates contained in the list called 'mountDates'. But it is not rendering the items. Here is my code:
import React, {useEffect} from 'react';
import {View, Text, StyleSheet} from 'react-native';
import {globalStyles} from '../../styles/global';
import AgendaItem from './agendaItem';
export default function Agenda({onDayChange, startDate, endDate}) {
const mountDates = [];
useEffect(() => {
const getDates = (startDate, endDate) => {
let currentDate = startDate;
console.log(startDate, endDate);
while (currentDate.getTime() <= endDate.getTime()) {
mountDates.push(new Date(currentDate));
currentDate.setDate(currentDate.getDate() + 1);
}
};
getDates(startDate, endDate);
}, []);
return (
<View style={styles.container}>
{mountDates.map((date, i) => {
return <AgendaItem key={i.toString()} date={date} />;
})}
</View>
);
}
Simply use React.useState. which will trigger re-render when all data is set.
import {View, Text, StyleSheet} from 'react-native';
import {globalStyles} from '../../styles/global';
import AgendaItem from './agendaItem';
export default function Agenda({onDayChange, startDate, endDate}) {
const [mountDates, setMountDates] = React.useState([]);
useEffect(() => {
const tempMountDates = [];
const getDates = (startDate, endDate) => {
let currentDate = startDate;
console.log(startDate, endDate);
while (currentDate.getTime() <= endDate.getTime()) {
tempMountDates.push(new Date(currentDate));
currentDate.setDate(currentDate.getDate() + 1);
}
};
getDates(startDate, endDate);
setMountDates();
}, []);
return (
<View style={styles.container}>
{mountDates.map((date, i) => {
return <AgendaItem key={i.toString()} date={date} />;
})}
</View>
);
}
I wanted to change my calendar component , from an old one to new one , they both exist on the website , but the new one isn't working, I want to make it work , when the user choose a date, it reacts with the website
this is my old one :
This is the Code :
import 'd3-transition';
import React, { Component } from 'react';
import { connect } from "react-redux";
import { setDatePrecision, nextDate, previousDate, loadWords, loadArticles } from "../redux/actions";
class DaySelector extends Component {
state = {
datePrecision: "day",
selectedDate: new Date()
};
render() {
const rthis = this.props;
const prev = () => {
rthis.previousDate();
this.props.loadWords();
this.props.loadArticles();
};
const next = () => {
rthis.nextDate();
this.props.loadWords();
this.props.loadArticles();
}
const dayPrecision = () => {
rthis.setDatePrecision("day");
this.props.loadWords();
this.props.loadArticles();
}
const monthPrecision = () => {
rthis.setDatePrecision("month");
this.props.loadWords();
this.props.loadArticles();
}
const current_date = this.props.selectedDate;
const datePrecision = this.props.datePrecision;
const year = current_date.getFullYear();
const month = current_date.getMonth() + 1;
const day = current_date.getDate();
return (
<div>
<a href="#day" onClick={dayPrecision}>day </a>
<a href="#month" onClick={monthPrecision}>month </a>
<a href="#prev" onClick={prev}><<<</a>
{datePrecision === "day" ? String(day).padStart(2, "0") + "/" : ""}{String(month).padStart(2, "0")}/{year}
<a href="#next" onClick={next}>>>></a>
</div>
);
}
}
const mapStateToProps = state => {
return {
selectedDate: state.wordsReducer.selectedDate,
datePrecision: state.wordsReducer.datePrecision,
}
};
export default connect(mapStateToProps, { setDatePrecision, nextDate, previousDate, loadWords, loadArticles })(DaySelector);
I want to replace it with this new Calendar :
this is the code of this component :
import React, { useState } from 'react';
import Calendar from 'react-calendar';
import 'react-calendar/dist/Calendar.css';
const MyCalendar = () => {
const [date, setDate] = useState(new Date());
const onChange = (date) => setDate(date);
return (
<div>
<h5 className="card-title mb-0">Calendar</h5>
<Calendar onChange={onChange} value={date} />
</div>
);
};
export default MyCalendar;
Those components are both on the website but I could not make it dynamically work,
I've install it from Here
Thank you !
Looks like you are missing to pass the prop from onChange, try:
<Calendar onChange={(value, event) => onChange(value)} value={date} />
or try:
<Calendar onChange={(value, event) => setDate(value)} value={date} />
i have todaytask on my app when i add task and date is current date then i want to show that task in today
MY ADD TASKS code:
import React, { useState } from 'react';
import uuid from 'react-uuid';
import { useSelector, useDispatch } from 'react-redux';
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import database from '../firebase/firebase';
import '../App.css';
import { SingleDatePicker } from 'react-dates';
import moment from 'moment';
import 'react-dates/initialize';
import 'react-dates/lib/css/_datepicker.css';
const AddTasks = () => {
const dispatch = useDispatch();
const newLocal = null;
const [selectedDate, setSelectedDate] = useState(moment());
const [task, setTask] = useState('');
const Date = moment();
const userId = useSelector(state => state.auth.uid);
const [focused, setFoucused]= useState(false);
const addTask = () => {
console.log(userId);
console.log('addedAt');
const payload = { id: uuid(), text: task, completed: false, addedAt: JSON.stringify(selectedDate)}
const dbtasksWrapper = database.ref().child(userId).child('tasks');
return dbtasksWrapper.child(payload.id).update(payload).then(() => {
setTask('');
setSelectedDate(null);
setFoucused(false)
dispatch({ type: "ADD_TASKS", payload })
})
}
return (
<form onSubmit={e => {
e.preventDefault(e.target.value);
addTask();
} }>
<input className="input-group-prepend" value={task} placeholder="Enter your Task" onChange={e => setTask(e.target.value)} />
<SingleDatePicker
date={selectedDate}
onDateChange={date => setSelectedDate(date)}
focused={focused}
onFocusChange={ focused => setFoucused( {focused: false} )}
/>
<br/>
<input className="btn btn-primary" type='submit' value='Submit' />
</form>
);
};
export default AddTasks;
then my TASKITEMS
import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import AddTasks from './AddTasks';
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import database from '../firebase/firebase';
import uuid from 'react-uuid';
const TaskItem = (props) => {
const dispatch = useDispatch();
const [task, setTask] = useState(props.task);
const [index, setIndex] = useState(props.index);
const [selectedDate, setSelectedDate] = useState(null);
const [editing, setEditing] = useState(false);
const [currentTask, setCurrentTask] = useState({});
const date = new Date()
const userId = useSelector(state => state.auth.uid);
const saveTask = () => {
setEditing(false);
const payload = { id: currentTask.id, text: currentTask.text, completed: false, addedAt: selectedDate }
const dbtasksWrapper = database.ref().child(userId).child('tasks');
dbtasksWrapper.child(payload.id).update(payload).then(() => {
dispatch({ type: "ADD_TASKS", payload });
})
}
const completeTask = () => {
const payload = { id: task.id, text: task.text, completed: true, addedAt: task.addedAt }
const dbtasksWrapper = database.ref().child(userId).child('tasks');
dbtasksWrapper.child(payload.id).update(payload).then(() => {
dispatch({ type: 'COMPLETE_TASK', payload })
})
}
const removeTask = (id) => {
console.log(id);
const dbtasksWrapper = database.ref().child(userId).child('tasks');
dbtasksWrapper.child(id).remove().then(() => {
dispatch({ type: 'REMOVE_TASK', id: id })
console.log('removed');
})
}
const editTask = (task) => {
setCurrentTask(task);
setEditing(true);
}
useEffect(() => {
setTask(props.task);
setIndex(props.index);
}, [props])
return (
<li
index={index}
key={task.id}
style={{
textDecoration: !task.completed ? 'inherit' : 'line-through'
}}
>
<div>
{
!task.completed ? <p></p> : <p className="alert alert-danger" >Task Completed </p>
// <div>
// {/* {Object.values(task.completed.toString()).length } */}
// </div>
}
</div>
<div className="border">
{editing ?
<div>
<input type='text' onChange={e => setCurrentTask({ ...currentTask, text: e.target.value })} value={currentTask.text} />
<DatePicker
className="input-group-prepend"
placeholderText="Enter task date "
selected={selectedDate}
onChange={(date) => setSelectedDate(date)}
minDate={date}
/>
</div>
:
if the date is current date then this should show in todaytasks
<div>
<h3> {task.text} </h3>
<p>{task.addedAt && task.addedAt.toString()}</p>
</div>
}
{editing ?
<div>
<input type='button' className='btn btn-primary' onClick={() => saveTask(task.id)} value='Save Task' />
<input type='button' className='btn btn-link' onClick={() => setEditing(false)} value='Cancel' />
</div>
:
<div>
<input className="btn btn-info btn-sm" type='button' value='CompleteTask' onClick={() => completeTask(task.id)} />
<input className="btn btn-danger btn-sm" type='button' value='Remove Task' onClick={() => removeTask(task.id)} />
<input type='button' className="btn btn-primary" onClick={() => editTask(task)} value='Edit Task' />
</div>
}
</div>
</li>
)
}
export default TaskItem;
and my TODAYTASK;
import React from 'react';
import { useSelector } from 'react-redux';
import AddTasks from '../components/AddTasks';
import TaskItem from './TaskItem';
import Header from './Header';
i think issue with date or need to fetch data fron taskitem but i am doing that it shows blank nothing
function isToday(date) {
var currentDate = new Date();
try {
return (
date.getFullYear() === currentDate.getFullYear() &&
date.getMonth() === currentDate.getMonth() &&
date.getDate() === currentDate.getDate()
)
} catch { }
return false;
}
export default function Today() {
const tasks = useSelector(state => state.tasks);
if (tasks) {
return (
<div>
<h1>Today</h1>
<AddTasks />
{Object.values(tasks).map((task, index) => {
var isTodayTask = isToday(task.addedAt);
console.log(isTodayTask);
return (
<ul>
{isTodayTask ? (
<div>
<TaskItem
task={task}
index={index}
/>
</div>
) : (
<div>
</div>
)}
</ul>
)
})}
</div>
)
} else {
return (
<div>
<h1>Today</h1>
<AddTasks />
<div>You have no tasks</div>
</div>
)
}
}
function isToday(date) {
var currentDate = new Date();
try {
return (
date.getFullYear() === currentDate.getFullYear() &&
date.getMonth() === currentDate.getMonth() &&
date.getDate() === currentDate.getDate()
)
} catch { }
return false;
}
Do you really need to wrap the statements into try..catch block? If an error is raised here you want to know about that. I believe that the problem is indeed with your date parameter and here's why:
const Date = moment();
that is the line from your AddTasks component where you set task.addedAt prop. Moment library uses built-in Date object under the hood. Seeing that Date is a built-in JS API the Date should not be redefined which you did in your AddTasks component. I am not sure how much it impacted the whole App but that line of code along might have broken the Date object which turned moments lib inoperational. Try digging up there.
Good luck!
function isToday(date) {
const taskDate = new Date(date);
const currentDate = new Date();
its done put date in new date done the work