@@ -11,6 +11,7 @@ import { invokeCallbacks } from "@/actions/helpers/invokeCallbacks";
1111import type { ContributionState } from "@/types/state/contribution" ;
1212import type { HostStore } from "@/types/state/host" ;
1313import { store } from "@/store" ;
14+ import { shallowEqualArrays } from "@/utils/compare" ;
1415
1516/**
1617 * A reference to a property of an input of a callback of a contribution.
@@ -43,29 +44,69 @@ export function handleHostStoreChange() {
4344 contributionsRecord ,
4445 hostStore ,
4546 ) ;
46- if ( callbackRequests && callbackRequests . length > 0 ) {
47- invokeCallbacks ( callbackRequests ) ;
47+
48+ const filteredCallbackRequests = callbackRequests . filter (
49+ ( callbackRequest ) : callbackRequest is CallbackRequest =>
50+ callbackRequest !== undefined ,
51+ ) ;
52+ if ( filteredCallbackRequests && filteredCallbackRequests . length > 0 ) {
53+ invokeCallbacks ( filteredCallbackRequests ) ;
4854 }
4955}
5056
51- function getCallbackRequests (
57+ // Exporting for testing only
58+ export function getCallbackRequests (
5259 propertyRefs : PropertyRef [ ] ,
5360 contributionsRecord : Record < string , ContributionState [ ] > ,
5461 hostStore : HostStore ,
55- ) : CallbackRequest [ ] {
56- return propertyRefs . map ( ( propertyRef ) => {
57- const contributions = contributionsRecord [ propertyRef . contribPoint ] ;
58- const contribution = contributions [ propertyRef . contribIndex ] ;
59- const callback = contribution . callbacks ! [ propertyRef . callbackIndex ] ;
60- const inputValues = getInputValues (
61- callback . inputs ! ,
62- contribution ,
62+ ) : ( CallbackRequest | undefined ) [ ] {
63+ const { lastCallbackInputValues } = store . getState ( ) ;
64+ return propertyRefs . map ( ( propertyRef ) =>
65+ getCallbackRequest (
66+ propertyRef ,
67+ lastCallbackInputValues ,
68+ contributionsRecord ,
6369 hostStore ,
64- ) ;
65- return { ...propertyRef , inputValues } ;
66- } ) ;
70+ ) ,
71+ ) ;
6772}
6873
74+ const getCallbackRequest = (
75+ propertyRef : PropertyRef ,
76+ lastCallbackInputValues : Record < string , unknown [ ] > ,
77+ contributionsRecord : Record < string , ContributionState [ ] > ,
78+ hostStore : HostStore ,
79+ ) => {
80+ const contribPoint : string = propertyRef . contribPoint ;
81+ const contribIndex : number = propertyRef . contribIndex ;
82+ const callbackIndex : number = propertyRef . callbackIndex ;
83+ const contributions = contributionsRecord [ contribPoint ] ;
84+ const contribution = contributions [ contribIndex ] ;
85+ const callback = contribution . callbacks ! [ callbackIndex ] ;
86+ const inputValues = getInputValues ( callback . inputs ! , contribution , hostStore ) ;
87+ const callbackId = `${ contribPoint } -${ contribIndex } -${ callbackIndex } ` ;
88+ const lastInputValues = lastCallbackInputValues [ callbackId ] ;
89+ if ( shallowEqualArrays ( lastInputValues , inputValues ) ) {
90+ // We no longer log, as the situation is quite common
91+ // Enable error logging for debugging only:
92+ // console.groupCollapsed("Skipping callback request");
93+ // console.debug("inputValues", inputValues);
94+ // console.groupEnd();
95+ return undefined ;
96+ }
97+ store . setState ( {
98+ lastCallbackInputValues : {
99+ ...lastCallbackInputValues ,
100+ [ callbackId ] : inputValues ,
101+ } ,
102+ } ) ;
103+ // Collect output IDs for updating their respective loading states
104+ const outputs = contribution . callbacks ?. [ callbackIndex ] [ "outputs" ] ;
105+ const outputIds : string [ ] =
106+ outputs ?. map ( ( output ) => output . id as string ) ?? [ ] ;
107+ return { ...propertyRef , inputValues, outputIds } ;
108+ } ;
109+
69110// TODO: use a memoized selector to get hostStorePropertyRefs
70111// Note that this will only be effective and once we split the
71112// static contribution infos and dynamic contribution states.
0 commit comments