From 1474833bb012fef43ad8f6579bfdc84fa4435d5a Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Tue, 9 Jan 2024 12:38:32 -0500 Subject: [PATCH] use memoization pattern for added notes' displayDt Instead of mutating an extra property 'displayDt' onto the entries, let's use a get function that returns the displayDt. This should fix issue (4) in https://github.com/e-mission/e-mission-docs/issues/1034. And let's also memoize that function so performance is not impacted --- www/js/survey/enketo/AddedNotesList.tsx | 33 ++++++++++++++----------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/www/js/survey/enketo/AddedNotesList.tsx b/www/js/survey/enketo/AddedNotesList.tsx index b50b00284..50161a3c6 100644 --- a/www/js/survey/enketo/AddedNotesList.tsx +++ b/www/js/survey/enketo/AddedNotesList.tsx @@ -14,19 +14,26 @@ import { useTranslation } from 'react-i18next'; import { EnketoUserInputEntry } from './enketoHelper'; import { logDebug } from '../../plugin/logger'; -type EntryWithDisplayDt = EnketoUserInputEntry & { displayDt?: { date: string; time: string } }; type Props = { timelineEntry: any; - additionEntries: EntryWithDisplayDt[]; + additionEntries: EnketoUserInputEntry[]; }; const AddedNotesList = ({ timelineEntry, additionEntries }: Props) => { const { t } = useTranslation(); const { addUserInputToEntry } = useContext(LabelTabContext); const [confirmDeleteModalVisible, setConfirmDeleteModalVisible] = useState(false); const [surveyModalVisible, setSurveyModalVisible] = useState(false); - const [editingEntry, setEditingEntry] = useState(null); + const [editingEntry, setEditingEntry] = useState(undefined); - function setDisplayDt(entry) { + const _cachedDts = {}; + function getDisplayDt(entry?: EnketoUserInputEntry) { + if (!entry) return ''; + + // memoization: if we've already calculated the displayDt for this entry, return it from cache + const cachedDt = _cachedDts[entry.metadata.write_ts]; // write_ts used as key since it's unique + if (cachedDt) return cachedDt; + + // otherwise, calculate it and cache it before returning it const timezone = timelineEntry.start_local_dt?.timezone || timelineEntry.enter_local_dt?.timezone || @@ -48,10 +55,10 @@ const AddedNotesList = ({ timelineEntry, additionEntries }: Props) => { .parseZone(stopTs * 1000) .tz(timezone) .format('LT'); - return (entry.displayDt = { - date: d, - time: begin + ' - ' + stop, - }); + + const dt = { date: d, time: begin + ' - ' + stop }; + _cachedDts[entry.metadata.write_ts] = dt; + return dt; } function deleteEntry(entry) { @@ -116,10 +123,8 @@ const AddedNotesList = ({ timelineEntry, additionEntries }: Props) => { onPress={() => editEntry(entry)} style={[styles.cell, { flex: 4 }]} textStyle={{ fontSize: 12, lineHeight: 12 }}> - {entry.displayDt?.date} - - {entry.displayDt?.time || (setDisplayDt(entry) && '')} - + {getDisplayDt(entry)?.date} + {getDisplayDt(entry)?.time} confirmDeleteEntry(entry)} @@ -151,8 +156,8 @@ const AddedNotesList = ({ timelineEntry, additionEntries }: Props) => { {t('diary.delete-entry-confirm')} {editingEntry?.data?.label} - {editingEntry?.displayDt?.date} - {editingEntry?.displayDt?.time} + {getDisplayDt(editingEntry)?.date} + {getDisplayDt(editingEntry)?.time}