here is my component that will render backend data that comes with this fetch request : export const fetchMonthThunk = createAsyncThunk(
'month/fetchTodayData',
async (month, { rejectWithValue }) => {
try {
const response = await fetchMonthAPI(month);
return response;
} catch (error) {
toast.error( Something's wrong. Check it later!
);
return rejectWithValue(error.message);
}
}
); export const selectorWaterMonth = state => state.dataUser.month;
import { handlerAddWater, handlerDeleteWater } from './handlers';
import { addWatersThunk, deleteEntryThunk, fetchMonthThunk } from './thunk';
import { createSlice } from '@reduxjs/toolkit';
import { fetchTodayThunk } from '../userData/thunk';
import { handleFetchToday, handleFetchMonth } from './handlers';
const initialState = { month: {}, today: { waterInputsForToday: [], dailyNormFulfillment: 0, }, };
const dataSlice = createSlice({ name: 'dataUser', initialState, reducers: {}, extraReducers: builder => { builder .addCase(fetchTodayThunk.fulfilled, handleFetchToday) .addCase(fetchMonthThunk.fulfilled, handleFetchMonth) .addCase(addWatersThunk.fulfilled, handlerAddWater) .addCase(deleteEntryThunk.fulfilled, handlerDeleteWater); }, });
export const dataReducer = dataSlice.reducer; export const handleFetchMonth = (state, { payload }) => { state.month = payload; }; and here is the components where it should be rendered: import React, { useState } from 'react'; import { RightArrow } from './img/RightArrow'; import { LeftArrow } from './img/LeftArrow';
import { ArrowButton, CalendarContainer, DayCell, DaysContainer, MonthNavigation, MonthControl, Month, DayPercent, Day, } from './Month.styled';
const Calendar = () => { const [currentDate, setCurrentDate] = useState(new Date());
const handleNextMonth = () => { setCurrentDate( new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1) ); };
const handlePrevMonth = () => { setCurrentDate( new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1) ); };
const getDaysInMonth = () => { return new Date( currentDate.getFullYear(), currentDate.getMonth() + 1, 0 ).getDate(); };
// // Mock backend data // const backendData = [ // { day: 1, percentage: 25 }, // { day: 2, percentage: 50 }, // { day: 3, percentage: 25 }, // { day: 4, percentage: 50 }, // { day: 5, percentage: 25 }, // { day: 6, percentage: 50 }, // { day: 7, percentage: 25 }, // { day: 8, percentage: 50 }, // { day: 9, percentage: 25 }, // { day: 10, percentage: 50 }, // { day: 11, percentage: 25 }, // { day: 12, percentage: 50 }, // { day: 13, percentage: 25 }, // { day: 14, percentage: 50 }, // { day: 15, percentage: 25 }, // { day: 16, percentage: 50 }, // { day: 17, percentage: 25 }, // { day: 18, percentage: 50 }, // { day: 19, percentage: 25 }, // { day: 20, percentage: 50 }, // { day: 21, percentage: 25 }, // { day: 22, percentage: 50 }, // { day: 23, percentage: 25 }, // { day: 24, percentage: 50 }, // { day: 25, percentage: 25 }, // { day: 26, percentage: 50 }, // { day: 27, percentage: 25 }, // { day: 28, percentage: 50 }, // { day: 29, percentage: 25 }, // { day: 30, percentage: 50 }, // // ... more data // ];
const renderDays = () => { const daysInMonth = getDaysInMonth(); const days = Array.from({ length: daysInMonth }, (_, index) => index + 1);
return days.map((day, index) => { const dataForDay = backendData.find(data => data.day === day); return ( <DayCell key={day}> <Day>{day}</Day> <DayPercent>{dataForDay && `${dataForDay.percentage}%`}</DayPercent> </DayCell> ); });
};
return ( Month {new Intl.DateTimeFormat('en-US', { month: 'long' }).format( currentDate )} {renderDays()} ); };
export default Calendar; in every daycell i need to render the percentage of the water drank on the specific day. here is what comes from the backend: [ { "date": "1, November", "waterRate": 2, "dailyNormFulfillment": 43, "servingOfWater": 4 }, { "date": "12, November", "waterRate": 2, "dailyNormFulfillment": 50, "servingOfWater": 4 } ] how do i do it?
To render the percentage of water drank on a specific day, you can follow these steps:
Here's a step-by-step guide to achieve this:
Extract Backend Data:
Calendar
component.Matching Data with Calendar Days:
Update Rendering Logic:
renderDays
function in the Calendar
component to use the matched backend data to display the percentage of water drank for each day.renderDays
function to include the water percentage from the matched backend data for each day.Here's an example of how the steps might be implemented:
Assume backendData contains the fetched backend data // Function to match backend data with calendar days const matchBackendDataWithDays = () => { const matchedData = new Map(); backendData.forEach(entry => { // Extract the day number from the date field const dayNumber = parseInt(entry.date.split(',')[0]); // Store the water percentage in the map using the day number as the key matchedData.set(dayNumber, entry.waterRate); }); return matchedData; }; const renderDays = () => { const daysInMonth = getDaysInMonth(); const days = Array.from({ length: daysInMonth }, (_, index) => index + 1); const matchedData = matchBackendDataWithDays(); return days.map(day => { const waterPercentage = matchedData.get(day); // Get the water percentage for the day return ( <DayCell key={day}> <Day>{day}</Day> <DayPercent>{waterPercentage && `${waterPercentage}%`}</DayPercent> </DayCell> ); }); };
With these changes, the renderDays
function now uses the matched backend data to display the water percentage for each day in the calendar.
By following these steps and modifying the Calendar
component accordingly, you can render the percentage of water drank on the specific day based on the data.
backendData should be filled from the fetch request i described ealier. so do i do it using disptach of fetchMonthThunk?
Yes, you're correct. To fetch data from the backend, you should dispatch fetchMonthThunk
. You should use this within a useEffect
Hook in your component, which fires when component mounts. Additionally, remember to import all necessary actions and objects from Redux in your file.
Here's how you could do it:
useDispatch
and useSelector
from react-redux
:import { useDispatch, useSelector } from 'react-redux';
fetchMonthThunk
and selectorWaterMonth
from your slice:import { fetchMonthThunk, selectorWaterMonth } from './path_to_your_slice_file'
useDispatch
inside the Calendar
component to get the dispatch
and initialize the backendData
with the state information:const Calendar = () => { const dispatch = useDispatch(); const backendData = useSelector(selectorWaterMonth); ... }
fetchMonthThunk
inside a useEffect
Hook:React.useEffect(() => { dispatch(fetchMonthThunk(your_month_arg_if_needed)); }, [dispatch]);
Now, backendData
will be updated automatically whenever your state updates and the component will re-render as needed Here your 'month' selector refers to the data fetched by 'fetchMonthThunk'. Make sure it is the data you want to represent as 'backendData'. Otherwise, define an appropriate selector.
Afterward, follow the same steps you were given to extract the day and percentage data from backendData
and display it as part of your Calendar
component.
import React, { useState, useEffect } from 'react';
import { RightArrow } from './img/RightArrow'; import { LeftArrow } from './img/LeftArrow'; import { useDispatch, useSelector } from 'react-redux';
import { ArrowButton, CalendarContainer, DayCell, DaysContainer, MonthNavigation, MonthControl, Month, DayPercent, Day, } from './Month.styled';
const Calendar = () => { const [currentDate, setCurrentDate] = useState(new Date()); const dispatch = useDispatch(); const backendData = useSelector(selectorWaterMonth);
useEffect(() => { dispatch(fetchMonthThunk()); }, [dispatch]);
const handleNextMonth = () => { setCurrentDate( new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1) ); };
const handlePrevMonth = () => { setCurrentDate( new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1) ); };
const getDaysInMonth = () => { return new Date( currentDate.getFullYear(), currentDate.getMonth() + 1, 0 ).getDate(); };
const matchBackendDataWithDays = () => { const matchedData = new Map();
backendData.forEach(entry => { const dayNumber = parseInt(entry.date.split(',')[0]); matchedData.set(dayNumber, entry.waterRate); }); return matchedData;
};
const renderDays = () => { const daysInMonth = getDaysInMonth(); const days = Array.from({ length: daysInMonth }, (_, index) => index + 1);
return days.map((day, index) => { const waterPercentage = matchedData.get(day); return ( <DayCell key={day}> <Day>{day}</Day> <DayPercent>{waterPercentage && `${waterPercentage}%`}</DayPercent> </DayCell> ); });
};
return ( Month {new Intl.DateTimeFormat('en-US', { month: 'long' }).format( currentDate )} {renderDays()} ); };
export default Calendar; is it correct? will i get data from the backend rendered in the percentange span in the calnder under each day?
Yes, this implementation is almost correct. However, there's a minor error - you are trying to use matchedData
within your renderDays
function but it's not available in that scope. You should call matchBackendDataWithDays
within your renderDays
function and assign its result to a new variable.
Here's the corrected version:
... const renderDays = () => { const daysInMonth = getDaysInMonth(); const days = Array.from({ length: daysInMonth }, (_, index) => index + 1); const matchedData = matchBackendDataWithDays(); return days.map((day, index) => { const waterPercentage = matchedData.get(day); return ( <DayCell key={day}> <Day>{day}</Day> <DayPercent>{waterPercentage && `${waterPercentage}%`}</DayPercent> </DayCell> ); }); }; ...
With this corrected implementation, your Calendar
component should now correctly fetch data from the backend upon mounting. It then matches this data with the days in the current month and renders the water percentage for each day under respective day in the calendar.
Just be sure to handle the case when backendData
is undefined
or empty, which could happen before the data has finished loading or if an error occurs. I assume selectorWaterMonth
and fetchMonthThunk
are correctly implemented and imported.