I am trying to build an analytics dashboard that allows user to filter project, toDate, fromDate, timeFrame. And also allow them to clearFilters
Depending upon the range between toDate and fromDate, TimeFrame will be disabled.
useEffect(() => {
// fetch data only once when any of those dependencies changes
// or multiple of them changes at the same time.
// fetchData();
// setItInTheContext();
renderCount.current = renderCount.current + 1;
console.log("API called", `${renderCount.current}`);
}, [project, fromDate, toDate, timeFrame]);
I want to fetch data only once when any of those dependencies changes or multiple of them changes at the same time.
Issue that I am facing is the delayed response & async behaviour of JS, (refer img.) since grouping data at the backend by Days take more time than weeks, I end up fetching data grouped by days and setting it to the context. Even though days is disabled for that date range.
Following codeSandbox mimics the issue. Please check the sandbox console. CODE_SANDBOX_Link: https://codesandbox.io/s/elated-glade-zbzmyv
I also tried putting all the dependencies in a single filterObject, but the behaviour is the exactly same. https://codesandbox.io/s/gracious-lehmann-4ftsqi
Following files are the same from the codesandbox.(Please ignore if you have already checkout the sandbox link)
// ProjectContext.js
import { createContext, useMemo, useState, useContext } from "react";
const ProjectContext = createContext(null);
export const ProjectProvider = ({ children }) => {
const [project, setProject] = useState("P1");
const date = new Date();
const [fromDate, setFromDate] = useState(
new Date(date.getFullYear(), date.getMonth(), 1)
);
const [toDate, setToDate] = useState(
new Date(date.getFullYear(), date.getMonth() + 1, 0)
);
const [timeFrame, setTimeFrame] = useState("years");
const value = useMemo(
() => ({project, setProject, fromDate, setFromDate, toDate, setToDate, timeFrame, setTimeFrame
}), [ project, setProject, fromDate, setFromDate, toDate, setToDate, timeFrame, setTimeFrame]
);
return (
<ProjectContext.Provider value={value}>{children}</ProjectContext.Provider>
);
};
export const useProject = () => {
const context = useContext(ProjectContext);
if (!context) {
throw new Error("ProjectContext must be used within ProjectProvider");
}
return context;
};
// App.js
import "./styles.css";
import { useEffect, useRef } from "react";
import { useProject } from "./ProjectContext";
export default function App() {
const { toDate, fromDate, project, timeFrame, setTimeFrame, setFromDate, setToDate, setProject } = useProject();
const renderCount = useRef(0);
useEffect(() => {
// fetch data only once when any of the following dependencies changes
// or multiple of them changes at the same time.
// fetchData();
// setItInTheContext()
renderCount.current = renderCount.current + 1;
console.log("API called", `${renderCount.current}`);
}, [project, fromDate, toDate, timeFrame]);
useEffect(() => {
setTimeFrame(`days ${renderCount.current}`);
}, [toDate, fromDate]);
const getStringDate = (date) => {
return new Date(date).toDateString();
};
return (
<div>
<input
type="submit"
onClick={(e) => setProject(`Project ${renderCount.current}`)}
label="Hello"
value="Select Project"
/>
<input
type="date"
value={fromDate}
onChange={(e) => setFromDate(e.target.value)}
placeholder="Enter from date"
/>
<input
type="date"
value={toDate}
onChange={(e) => setToDate(e.target.value)}
placeholder="Enter to date"
/>
<input
type="submit"
value="Change timeFrame"
onClick={() => {
setTimeFrame(`weeks ${renderCount.current}`);
}}
/>
<input
type="submit"
value="Clear Filter"
onClick={() => {
setFromDate(new Date());
setToDate(new Date());
}}
/>
<p>Render Count : {renderCount.current}</p>
<p>Project : {project}</p>
<p>To Date : {getStringDate(toDate)}</p>
<p>From Date :{getStringDate(fromDate)}</p>
<p>TimeFrame : {timeFrame}</p>
</div>
);
}
Thank you in advance..!!