Generated state keys for selector resolution do not account for varying types of recordKey #52106
Labels
Needs Technical Feedback
Needs testing from a developer perspective.
[Package] Core data
/packages/core-data
[Package] Data
/packages/data
[Status] In Progress
Tracking issues with work in progress
[Type] Bug
An existing feature does not function as intended
Calling
getEntityRecord
on a populated Redux cache (can) result in unnecessary network requests.This is dependent on whether a consumer passes the 3rd
recordKey
argument as aString
or anInteger
.Expected behaviour: if a record already exists in state, a call to select that record by ID should not result in a network request to retrieve that record.
Actual behaviour: if a record already exists in state, a
getEntityRecord
call to select that record by ID using a string-based ID results in an additional network request.Replication
You can replicate as follows:
Esc
to also open theConsole
tab below it.wp.data.select('core').getEntityRecords('postType', 'wp_navigation')
. You should seenull
and then running it again you should see results. This has populated thecore/data
state with entities of that type.id
s of those records.getEntityRecords
resolves thegetEntityRecord
selectors.wp.data.select('core').getEntityRecord('postType', 'wp_navigation','{YOUR_RECORD_ID}')
wp.data.select('core').getEntityRecord('postType', 'wp_navigation',{YOUR_RECORD_ID})
Screencapture
Screen.Capture.on.2023-06-29.at.10-15-18.mp4
Explanation
@wordpress/data has a mechanism whereby the next resolution state of a selector is determined by setting a
status
prop on avalue
in a (special kind of)Map
object.This map is is "keyed" by the selector's args as an array (remember
Map
can have many different types of keys compared to plain objects).For example a call to
getEntityRecords('postType', 'wp_navigation')
would result in a "key" array for a given record that might look like this -['postType', 'wp_navigation', 379)]
.When it comes time to determine whether a given resolver is "resolved", we check the same
Map
for a key which matches the given selector's args.gutenberg/packages/data/src/redux-store/metadata/selectors.js
Lines 22 to 29 in 3b7902e
However the bug occurs when you pass different types as the 3rd argument to
getEntityRecord()
.The reason this happens is that the
args
being set in theEquivalentKeyMap
cache have different types for the 3rd (recordKey
) argument. This is because consumers often callgetEntityRecords
interchangeably, passing the 3rd (recordKey
) argument as either a number of a string (note it's also due to the waygetEntityRecords
resolves thegetEntityRecord
selector - see below).This means that the call to
...tries to get a value using the key
['postType', 'wp_navigation', '379')]
but the key is actually using the integer form['postType', 'wp_navigation', 379)]
so no match occurs.This causes the selector to not be resolved and thus the network request is dispatched. This is wrong as the resolver should in fact be resolved.
It's worth noting that the reason a
integer
sends up in the state is due to how we resolve thegetEntityRecord
(singular) selector within thegetEntityRecords
(plural) resolver:gutenberg/packages/core-data/src/resolvers.js
Lines 203 to 206 in 3b7902e
The
record[ key ]
part will always result in a integer because the value of theid
property of the REST API response is always a int and not a string.Solution
I have a fix whereby I patched the
selectorArgsToStateKey
to convert any "numeric" strings in theargs
array into their integer equivalents.This ensures that however
getEntityRecord
is called the cache always sets/gets using the same type.However it might be a bit drastic and I'm not sure of any side effects.
The text was updated successfully, but these errors were encountered: