@@ -146,6 +146,16 @@ const reduceCollectionWithSelector = (collection, selector, withOnyxInstanceStat
146146 { } ,
147147 ) ;
148148
149+ /**
150+ * Returns if the key is a computed key.
151+ *
152+ * @param {Mixed } key
153+ * @returns {boolean }
154+ */
155+ function isComputedKey ( key ) {
156+ return typeof key === 'object' && 'compute' in key ;
157+ }
158+
149159/**
150160 * Get some data from the store
151161 *
@@ -251,10 +261,6 @@ function isSafeEvictionKey(testKey) {
251261 return _ . some ( evictionAllowList , ( key ) => isKeyMatch ( key , testKey ) ) ;
252262}
253263
254- function isComputedKey ( key ) {
255- return typeof key === 'object' && 'compute' in key ;
256- }
257-
258264function getCacheKey ( key ) {
259265 return isComputedKey ( key ) ? key . cacheKey : key ;
260266}
@@ -279,7 +285,6 @@ function tryGetCachedValue(key, mapping = {}) {
279285 const dependencies = _ . mapObject ( key . dependencies || { } , ( dependencyKey ) =>
280286 tryGetCachedValue (
281287 dependencyKey ,
282-
283288 // TODO: We could support full mapping here.
284289 { key : dependencyKey } ,
285290 ) ,
@@ -853,6 +858,15 @@ function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
853858 . then ( ( val ) => sendDataToConnection ( mapping , val , undefined , true ) ) ;
854859}
855860
861+ function computeAndSendData ( mapping , dependencies ) {
862+ let val = cache . getValue ( mapping . key . cacheKey ) ;
863+ if ( val === undefined ) {
864+ val = mapping . key . compute ( dependencies ) ;
865+ cache . set ( mapping . key . cacheKey , val ) ;
866+ }
867+ sendDataToConnection ( mapping , val , mapping . key . cacheKey , true ) ;
868+ }
869+
856870/**
857871 * Subscribes a react component's state directly to a store key
858872 *
@@ -886,43 +900,49 @@ function connect(mapping) {
886900 callbackToStateMapping [ connectionID ] = mapping ;
887901 callbackToStateMapping [ connectionID ] . connectionID = connectionID ;
888902
889- if ( mapping . initWithStoredValues === false ) {
903+ if ( isComputedKey ( mapping . key ) ) {
904+ deferredInitTask . promise
905+ . then ( ( ) => addKeyToRecentlyAccessedIfNeeded ( mapping ) )
906+ . then ( ( ) => {
907+ const mappingDependencies = mapping . key . dependencies || { } ;
908+ const dependenciesCount = _ . size ( mappingDependencies ) ;
909+ if ( dependenciesCount === 0 ) {
910+ // If we have no dependencies we can send the computed value immediately.
911+ computeAndSendData ( mapping , { } ) ;
912+ } else {
913+ callbackToStateMapping [ connectionID ] . dependencyConnections = [ ] ;
914+
915+ const dependencies = { } ;
916+ _ . each ( mappingDependencies , ( dependency , mappingKey ) => {
917+ // Create a mapping of dependent cache keys so when a key changes, all dependent keys
918+ // can also be cleared from the cache.
919+ const cacheKey = getCacheKey ( dependency ) ;
920+ dependentCacheKeys [ cacheKey ] = dependentCacheKeys [ cacheKey ] || new Set ( ) ;
921+ dependentCacheKeys [ cacheKey ] . add ( mapping . key . cacheKey ) ;
922+
923+ // Connect to dependencies.
924+ const dependencyConnection = connect ( {
925+ key : dependency ,
926+ waitForCollectionCallback : true ,
927+ callback : ( value ) => {
928+ dependencies [ mappingKey ] = value ;
929+
930+ // Once all dependencies are ready, compute the value and send it to the connection.
931+ if ( _ . size ( dependencies ) === dependenciesCount ) {
932+ computeAndSendData ( mapping , dependencies ) ;
933+ }
934+ } ,
935+ } ) ;
936+
937+ // Store dependency connections so we can disconnect them later.
938+ callbackToStateMapping [ connectionID ] . dependencyConnections . push ( dependencyConnection ) ;
939+ } ) ;
940+ }
941+ } ) ;
890942 return connectionID ;
891943 }
892944
893- if ( isComputedKey ( mapping . key ) ) {
894- deferredInitTask . promise . then ( ( ) => {
895- callbackToStateMapping [ connectionID ] . dependencyConnections = [ ] ;
896-
897- const mappingDependencies = mapping . key . dependencies || { } ;
898- const dependenciesCount = _ . size ( mappingDependencies ) ;
899- const dependencies = { } ;
900- _ . each ( mappingDependencies , ( dependency , mappingKey ) => {
901- const cacheKey = getCacheKey ( dependency ) ;
902- dependentCacheKeys [ cacheKey ] = dependentCacheKeys [ cacheKey ] || new Set ( ) ;
903- dependentCacheKeys [ cacheKey ] . add ( mapping . key . cacheKey ) ;
904- const dependencyConnection = connect ( {
905- key : dependency ,
906- waitForCollectionCallback : true ,
907- callback : ( value ) => {
908- dependencies [ mappingKey ] = value ;
909-
910- if ( _ . size ( dependencies ) === dependenciesCount ) {
911- let val = cache . getValue ( mapping . key . cacheKey ) ;
912- if ( val === undefined ) {
913- val = mapping . key . compute ( dependencies ) ;
914- cache . set ( mapping . key . cacheKey , val ) ;
915- }
916-
917- sendDataToConnection ( mapping , val , mapping . key . cacheKey , true ) ;
918- }
919- } ,
920- } ) ;
921-
922- // TODO: Disconnect those on disconnect.
923- callbackToStateMapping [ connectionID ] . dependencyConnections . push ( dependencyConnection ) ;
924- } ) ;
925- } ) ;
945+ if ( mapping . initWithStoredValues === false ) {
926946 return connectionID ;
927947 }
928948
0 commit comments