mirror of
https://github.com/actualbudget/actual.git
synced 2026-04-30 10:14:53 -05:00
Fix react-hooks/exhaustive-deps error on TransactionsTable.jsx (#4268)
* Fix react-hooks/exhaustive-deps error on TransactionsTable.jsx * Release notes * Fix lint
This commit is contained in:
committed by
GitHub
parent
a085945898
commit
d902c38253
@@ -792,9 +792,6 @@ export default [
|
|||||||
'packages/desktop-client/src/components/spreadsheet/useSheetValue.ts',
|
'packages/desktop-client/src/components/spreadsheet/useSheetValue.ts',
|
||||||
'packages/desktop-client/src/components/table.tsx',
|
'packages/desktop-client/src/components/table.tsx',
|
||||||
'packages/desktop-client/src/components/transactions/TransactionList.jsx',
|
'packages/desktop-client/src/components/transactions/TransactionList.jsx',
|
||||||
'packages/desktop-client/src/components/transactions/TransactionsTable.jsx',
|
|
||||||
'packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx',
|
|
||||||
// 'packages/desktop-client/src/hooks/useAccounts.ts',
|
|
||||||
'packages/desktop-client/src/hooks/useCategories.ts',
|
'packages/desktop-client/src/hooks/useCategories.ts',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import React, {
|
|||||||
useRef,
|
useRef,
|
||||||
useMemo,
|
useMemo,
|
||||||
useCallback,
|
useCallback,
|
||||||
useLayoutEffect,
|
|
||||||
useEffect,
|
useEffect,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
@@ -1856,28 +1855,35 @@ function TransactionTableInner({
|
|||||||
setScrollWidth(!width ? 0 : width);
|
setScrollWidth(!width ? 0 : width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
onCloseAddTransaction: onCloseAddTransactionProp,
|
||||||
|
onNavigateToTransferAccount: onNavigateToTransferAccountProp,
|
||||||
|
onNavigateToSchedule: onNavigateToScheduleProp,
|
||||||
|
onNotesTagClick: onNotesTagClickProp,
|
||||||
|
} = props;
|
||||||
|
|
||||||
const onNavigateToTransferAccount = useCallback(
|
const onNavigateToTransferAccount = useCallback(
|
||||||
accountId => {
|
accountId => {
|
||||||
props.onCloseAddTransaction();
|
onCloseAddTransactionProp();
|
||||||
props.onNavigateToTransferAccount(accountId);
|
onNavigateToTransferAccountProp(accountId);
|
||||||
},
|
},
|
||||||
[props.onCloseAddTransaction, props.onNavigateToTransferAccount],
|
[onCloseAddTransactionProp, onNavigateToTransferAccountProp],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onNavigateToSchedule = useCallback(
|
const onNavigateToSchedule = useCallback(
|
||||||
scheduleId => {
|
scheduleId => {
|
||||||
props.onCloseAddTransaction();
|
onCloseAddTransactionProp();
|
||||||
props.onNavigateToSchedule(scheduleId);
|
onNavigateToScheduleProp(scheduleId);
|
||||||
},
|
},
|
||||||
[props.onCloseAddTransaction, props.onNavigateToSchedule],
|
[onCloseAddTransactionProp, onNavigateToScheduleProp],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onNotesTagClick = useCallback(
|
const onNotesTagClick = useCallback(
|
||||||
noteTag => {
|
noteTag => {
|
||||||
props.onCloseAddTransaction();
|
onCloseAddTransactionProp();
|
||||||
props.onNotesTagClick(noteTag);
|
onNotesTagClickProp(noteTag);
|
||||||
},
|
},
|
||||||
[props.onCloseAddTransaction, props.onNotesTagClick],
|
[onCloseAddTransactionProp, onNotesTagClickProp],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -2113,6 +2119,7 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
const [newTransactions, setNewTransactions] = useState(null);
|
const [newTransactions, setNewTransactions] = useState(null);
|
||||||
const [prevIsAdding, setPrevIsAdding] = useState(false);
|
const [prevIsAdding, setPrevIsAdding] = useState(false);
|
||||||
const splitsExpanded = useSplitsExpanded();
|
const splitsExpanded = useSplitsExpanded();
|
||||||
|
const splitsExpandedDispatch = splitsExpanded.dispatch;
|
||||||
const prevSplitsExpanded = useRef(null);
|
const prevSplitsExpanded = useRef(null);
|
||||||
|
|
||||||
const tableRef = useRef(null);
|
const tableRef = useRef(null);
|
||||||
@@ -2191,6 +2198,8 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
);
|
);
|
||||||
}, [props.transactions, props.payees, props.accounts]);
|
}, [props.transactions, props.payees, props.accounts]);
|
||||||
|
|
||||||
|
const hasPrevSplitsExpanded = prevSplitsExpanded.current;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// If it's anchored that means we've also disabled animations. To
|
// If it's anchored that means we've also disabled animations. To
|
||||||
// reduce the chance for side effect collision, only do this if
|
// reduce the chance for side effect collision, only do this if
|
||||||
@@ -2199,7 +2208,7 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
tableRef.current.unanchor();
|
tableRef.current.unanchor();
|
||||||
tableRef.current.setRowAnimation(true);
|
tableRef.current.setRowAnimation(true);
|
||||||
}
|
}
|
||||||
}, [prevSplitsExpanded.current]);
|
}, [hasPrevSplitsExpanded]);
|
||||||
|
|
||||||
const newNavigator = useTableNavigator(
|
const newNavigator = useTableNavigator(
|
||||||
newTransactions,
|
newTransactions,
|
||||||
@@ -2217,14 +2226,12 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
const [_, forceRerender] = useState({});
|
const [_, forceRerender] = useState({});
|
||||||
const selectedItems = useSelectedItems();
|
const selectedItems = useSelectedItems();
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
latestState.current = {
|
||||||
latestState.current = {
|
newTransactions,
|
||||||
newTransactions,
|
newNavigator,
|
||||||
newNavigator,
|
tableNavigator,
|
||||||
tableNavigator,
|
transactions: props.transactions,
|
||||||
transactions: props.transactions,
|
};
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Derive new transactions from the `isAdding` prop
|
// Derive new transactions from the `isAdding` prop
|
||||||
if (prevIsAdding !== props.isAdding) {
|
if (prevIsAdding !== props.isAdding) {
|
||||||
@@ -2239,32 +2246,30 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
setPrevIsAdding(props.isAdding);
|
setPrevIsAdding(props.isAdding);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
if (shouldAdd.current) {
|
||||||
if (shouldAdd.current) {
|
if (newTransactions[0].account == null) {
|
||||||
if (newTransactions[0].account == null) {
|
dispatch(
|
||||||
dispatch(
|
addNotification({
|
||||||
addNotification({
|
type: 'error',
|
||||||
type: 'error',
|
message: 'Account is a required field',
|
||||||
message: 'Account is a required field',
|
}),
|
||||||
}),
|
);
|
||||||
);
|
newNavigator.onEdit('temp', 'account');
|
||||||
newNavigator.onEdit('temp', 'account');
|
} else {
|
||||||
} else {
|
const transactions = latestState.current.newTransactions;
|
||||||
const transactions = latestState.current.newTransactions;
|
const lastDate = transactions.length > 0 ? transactions[0].date : null;
|
||||||
const lastDate = transactions.length > 0 ? transactions[0].date : null;
|
setNewTransactions(
|
||||||
setNewTransactions(
|
makeTemporaryTransactions(
|
||||||
makeTemporaryTransactions(
|
props.currentAccountId,
|
||||||
props.currentAccountId,
|
props.currentCategoryId,
|
||||||
props.currentCategoryId,
|
lastDate,
|
||||||
lastDate,
|
),
|
||||||
),
|
);
|
||||||
);
|
newNavigator.onEdit('temp', 'date');
|
||||||
newNavigator.onEdit('temp', 'date');
|
props.onAdd(transactions);
|
||||||
props.onAdd(transactions);
|
|
||||||
}
|
|
||||||
shouldAdd.current = false;
|
|
||||||
}
|
}
|
||||||
});
|
shouldAdd.current = false;
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (savePending.current && afterSaveFunc.current) {
|
if (savePending.current && afterSaveFunc.current) {
|
||||||
@@ -2273,7 +2278,7 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
savePending.current = false;
|
savePending.current = false;
|
||||||
}, [newTransactions, props.transactions]);
|
}, [newTransactions, props, props.transactions]);
|
||||||
|
|
||||||
function getFieldsNewTransaction(item) {
|
function getFieldsNewTransaction(item) {
|
||||||
const fields = [
|
const fields = [
|
||||||
@@ -2410,7 +2415,20 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
// effect we want to run. We have to wait for all updates to be
|
// effect we want to run. We have to wait for all updates to be
|
||||||
// committed (the input could still be saving a value).
|
// committed (the input could still be saving a value).
|
||||||
forceRerender({});
|
forceRerender({});
|
||||||
}, [props.onAdd, newNavigator.onEdit]);
|
}, []);
|
||||||
|
|
||||||
|
const {
|
||||||
|
onSave: onSaveProp,
|
||||||
|
onApplyRules: onApplyRulesProp,
|
||||||
|
onBatchDelete,
|
||||||
|
onBatchDuplicate,
|
||||||
|
onBatchLinkSchedule,
|
||||||
|
onBatchUnlinkSchedule,
|
||||||
|
onCreateRule: onCreateRuleProp,
|
||||||
|
onScheduleAction: onScheduleActionProp,
|
||||||
|
onMakeAsNonSplitTransactions: onMakeAsNonSplitTransactionsProp,
|
||||||
|
onSplit: onSplitProp,
|
||||||
|
} = props;
|
||||||
|
|
||||||
const onSave = useCallback(
|
const onSave = useCallback(
|
||||||
async (transaction, subtransactions = null, updatedFieldName = null) => {
|
async (transaction, subtransactions = null, updatedFieldName = null) => {
|
||||||
@@ -2421,8 +2439,8 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
: transaction;
|
: transaction;
|
||||||
|
|
||||||
if (isTemporaryId(transaction.id)) {
|
if (isTemporaryId(transaction.id)) {
|
||||||
if (props.onApplyRules) {
|
if (onApplyRulesProp) {
|
||||||
groupedTransaction = await props.onApplyRules(
|
groupedTransaction = await onApplyRulesProp(
|
||||||
groupedTransaction,
|
groupedTransaction,
|
||||||
updatedFieldName,
|
updatedFieldName,
|
||||||
);
|
);
|
||||||
@@ -2437,48 +2455,69 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
props.onSave(groupedTransaction);
|
onSaveProp(groupedTransaction);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[props.onSave],
|
[onSaveProp, onApplyRulesProp],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onDelete = useCallback(id => {
|
const onDelete = useCallback(
|
||||||
const temporary = isTemporaryId(id);
|
id => {
|
||||||
|
const temporary = isTemporaryId(id);
|
||||||
|
|
||||||
if (temporary) {
|
if (temporary) {
|
||||||
const newTrans = latestState.current.newTransactions;
|
const newTrans = latestState.current.newTransactions;
|
||||||
|
|
||||||
if (id === newTrans[0].id) {
|
if (id === newTrans[0].id) {
|
||||||
// You can never delete the parent new transaction
|
// You can never delete the parent new transaction
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setNewTransactions(deleteTransaction(newTrans, id).data);
|
||||||
|
} else {
|
||||||
|
onBatchDelete([id]);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
[onBatchDelete],
|
||||||
|
);
|
||||||
|
|
||||||
setNewTransactions(deleteTransaction(newTrans, id).data);
|
const onDuplicate = useCallback(
|
||||||
} else {
|
id => {
|
||||||
props.onBatchDelete([id]);
|
onBatchDuplicate([id]);
|
||||||
}
|
},
|
||||||
}, []);
|
[onBatchDuplicate],
|
||||||
|
);
|
||||||
|
|
||||||
const onDuplicate = useCallback(id => {
|
const onLinkSchedule = useCallback(
|
||||||
props.onBatchDuplicate([id]);
|
id => {
|
||||||
}, []);
|
onBatchLinkSchedule([id]);
|
||||||
|
},
|
||||||
const onLinkSchedule = useCallback(id => {
|
[onBatchLinkSchedule],
|
||||||
props.onBatchLinkSchedule([id]);
|
);
|
||||||
}, []);
|
const onUnlinkSchedule = useCallback(
|
||||||
const onUnlinkSchedule = useCallback(id => {
|
id => {
|
||||||
props.onBatchUnlinkSchedule([id]);
|
onBatchUnlinkSchedule([id]);
|
||||||
}, []);
|
},
|
||||||
const onCreateRule = useCallback(id => {
|
[onBatchUnlinkSchedule],
|
||||||
props.onCreateRule([id]);
|
);
|
||||||
}, []);
|
const onCreateRule = useCallback(
|
||||||
const onScheduleAction = useCallback((action, id) => {
|
id => {
|
||||||
props.onScheduleAction(action, [id]);
|
onCreateRuleProp([id]);
|
||||||
}, []);
|
},
|
||||||
const onMakeAsNonSplitTransactions = useCallback(id => {
|
[onCreateRuleProp],
|
||||||
props.onMakeAsNonSplitTransactions([id]);
|
);
|
||||||
}, []);
|
const onScheduleAction = useCallback(
|
||||||
|
(action, id) => {
|
||||||
|
onScheduleActionProp(action, [id]);
|
||||||
|
},
|
||||||
|
[onScheduleActionProp],
|
||||||
|
);
|
||||||
|
const onMakeAsNonSplitTransactions = useCallback(
|
||||||
|
id => {
|
||||||
|
onMakeAsNonSplitTransactionsProp([id]);
|
||||||
|
},
|
||||||
|
[onMakeAsNonSplitTransactionsProp],
|
||||||
|
);
|
||||||
|
|
||||||
const onSplit = useMemo(() => {
|
const onSplit = useMemo(() => {
|
||||||
return id => {
|
return id => {
|
||||||
@@ -2501,9 +2540,9 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const trans = latestState.current.transactions.find(t => t.id === id);
|
const trans = latestState.current.transactions.find(t => t.id === id);
|
||||||
const newId = props.onSplit(id);
|
const newId = onSplitProp(id);
|
||||||
|
|
||||||
splitsExpanded.dispatch({ type: 'open-split', id: trans.id });
|
splitsExpandedDispatch({ type: 'open-split', id: trans.id });
|
||||||
|
|
||||||
const { tableNavigator } = latestState.current;
|
const { tableNavigator } = latestState.current;
|
||||||
if (trans.amount === null) {
|
if (trans.amount === null) {
|
||||||
@@ -2513,12 +2552,19 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [props.onSplit, splitsExpanded.dispatch]);
|
}, [onSplitProp, splitsExpandedDispatch]);
|
||||||
|
|
||||||
|
const { onAddSplit: onAddSplitProp } = props;
|
||||||
|
|
||||||
const onAddSplit = useCallback(
|
const onAddSplit = useCallback(
|
||||||
id => {
|
id => {
|
||||||
|
const {
|
||||||
|
tableNavigator,
|
||||||
|
newNavigator,
|
||||||
|
newTransactions: newTrans,
|
||||||
|
} = latestState.current;
|
||||||
|
|
||||||
if (isTemporaryId(id)) {
|
if (isTemporaryId(id)) {
|
||||||
const newTrans = latestState.current.newTransactions;
|
|
||||||
const { data, diff } = addSplitTransaction(newTrans, id);
|
const { data, diff } = addSplitTransaction(newTrans, id);
|
||||||
setNewTransactions(data);
|
setNewTransactions(data);
|
||||||
newNavigator.onEdit(
|
newNavigator.onEdit(
|
||||||
@@ -2526,19 +2572,19 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
latestState.current.newNavigator.focusedField,
|
latestState.current.newNavigator.focusedField,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const newId = props.onAddSplit(id);
|
const newId = onAddSplitProp(id);
|
||||||
tableNavigator.onEdit(
|
tableNavigator.onEdit(
|
||||||
newId,
|
newId,
|
||||||
latestState.current.tableNavigator.focusedField,
|
latestState.current.tableNavigator.focusedField,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[props.onAddSplit],
|
[onAddSplitProp],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onDistributeRemainder = useCallback(
|
const onDistributeRemainder = useCallback(
|
||||||
async id => {
|
async id => {
|
||||||
const { transactions, tableNavigator, newTransactions } =
|
const { transactions, newNavigator, tableNavigator, newTransactions } =
|
||||||
latestState.current;
|
latestState.current;
|
||||||
|
|
||||||
const targetTransactions = isTemporaryId(id)
|
const targetTransactions = isTemporaryId(id)
|
||||||
@@ -2592,7 +2638,7 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[latestState],
|
[onSave],
|
||||||
);
|
);
|
||||||
|
|
||||||
function onCloseAddTransaction() {
|
function onCloseAddTransaction() {
|
||||||
@@ -2606,8 +2652,8 @@ export const TransactionTable = forwardRef((props, ref) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onToggleSplit = useCallback(
|
const onToggleSplit = useCallback(
|
||||||
id => splitsExpanded.dispatch({ type: 'toggle-split', id }),
|
id => splitsExpandedDispatch({ type: 'toggle-split', id }),
|
||||||
[splitsExpanded.dispatch],
|
[splitsExpandedDispatch],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -130,13 +130,14 @@ type LiveTransactionTableProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function LiveTransactionTable(props: LiveTransactionTableProps) {
|
function LiveTransactionTable(props: LiveTransactionTableProps) {
|
||||||
const [transactions, setTransactions] = useState(props.transactions);
|
const { transactions: transactionsProp, onTransactionsChange } = props;
|
||||||
|
|
||||||
|
const [transactions, setTransactions] = useState(transactionsProp);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (transactions === props.transactions) return;
|
if (transactions === transactionsProp) return;
|
||||||
props.onTransactionsChange?.(transactions);
|
onTransactionsChange?.(transactions);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
}, [transactions, transactionsProp, onTransactionsChange]);
|
||||||
}, [transactions]);
|
|
||||||
|
|
||||||
const onSplit = (id: string) => {
|
const onSplit = (id: string) => {
|
||||||
const { data, diff } = splitTransaction(transactions, id);
|
const { data, diff } = splitTransaction(transactions, id);
|
||||||
|
|||||||
6
upcoming-release-notes/4268.md
Normal file
6
upcoming-release-notes/4268.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
category: Maintenance
|
||||||
|
authors: [joel-jeremy]
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix react-hooks/exhaustive-deps error on TransactionsTable.jsx
|
||||||
Reference in New Issue
Block a user