Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core data: selectors return stale data despite different query parameters #56355

Open
ramonjd opened this issue Nov 21, 2023 · 3 comments
Open
Labels
[Package] Core data /packages/core-data [Type] Bug An existing feature does not function as intended

Comments

@ramonjd
Copy link
Member

ramonjd commented Nov 21, 2023

Description

Unresolved core data selectors will return null if records are not found in state. They'll then go off and "resolve" the query (fetch the data from the API) and update the state.

When using query params such as per_page — params that normally should trigger a new API call given that it can request records not yet available in the state — the selectors will not return null but return whatever it finds in the state until the resolvers are done.

From what I can gather, the queries reducer state for each entity creates "stableKeys" to cache IDs for certain queries. Currently only _fields and includes queries are cached, otherwise the key is "".

Props to @andrewserong for finding and reporting here: #54046 (review)

Step-by-step reproduction instructions

Make sure you have a few posts or pages or other entities saved.

In your browser's console, fetch those entities:

 // 1. API call, returns null
await wp.data.select( 'core' ).getEntityRecords( 'postType', 'post', { per_page: 2 } )

 // 2. No API call, returns expected results
await wp.data.select( 'core' ).getEntityRecords( 'postType', 'post', { per_page: 2 } )

 // 3.  API call, returns results from previous command 2
await wp.data.select( 'core' ).getEntityRecords( 'postType', 'post', { per_page: 3 } )

 // 4.  No API call, returns expected results
await wp.data.select( 'core' ).getEntityRecords( 'postType', 'post', { per_page: 3 } )

 // 5.  API call, returns results from previous command 3
await wp.data.select( 'core' ).getEntityRecords( 'postType', 'post', { per_page: 4 } )

 // 6.  No API call, returns expected results
await wp.data.select( 'core' ).getEntityRecords( 'postType', 'post', { per_page: 4 } ) 

What I expected

For commands 3 and 4, we'd expect either null or [] or some other result to indicate that the selector cannot find these records.

Instead it returns the last known query.

Screenshots, screen recording, code snippet

No response

Environment info

  • WordPress 6.5 alpha
  • Gutenberg latest (trunk)

Please confirm that you have searched existing issues in the repo.

Yes

Please confirm that you have tested with all plugins deactivated except Gutenberg.

Yes

@ramonjd
Copy link
Member Author

ramonjd commented Dec 1, 2023

I was having another look at this and I think I've narrowed it down to the getQueriedItemsUncached selector.

getQueriedItemsUncached works as expected with the information it's given.

For example, requesting getEntityRecords( 'postType', 'post', { per_page: 5 } ), it will search the state and find items that are "completed", a.k.a fetched and resolved, and return them.

getQueriedItemsUncached doesn't care that the number of items it returns doesn't match the per_page value, it'll return as many as it can within the query parameters.

So that's why getEntityRecords( 'postType', 'post', { per_page: 5 } ) might just return two items, because getQueriedItemsUncached will do its best until the new response hits the state.

What getQueriedItemsUncached doesn't know, is whether a request for that query is still resolving. The server might load enough records to satisfy the query, but it might not.

If getQueriedItemsUncached did know that the query has resolved, and the items it finds don't match the query, e.g., items.length !== per_page it could return [] or null while the resolver is working.

If it knew that a corresponding query had already been resolved, it could then confidently return as many as it can find, e.g., the full set of 5 records for the page, or, if it's reached the last page, in a set with < 5 records.

@kozack-webspark
Copy link

I have similar issue in latest WordPress 6.5.4. Calling getEntityRecords returns values only from store. Not from actual API call.

Assume I Have a few post tags registered.

// First load
// API call. Promise return null
await wp.data.select('core').getEntityRecords('taxonomy', 'post_tag', {per_page: 2})

// No API call. Promise return array of 2 items
await wp.data.select('core').getEntityRecords('taxonomy', 'post_tag', {per_page: 2})

// Attempt to load next page
// API call. Promise return an empty array
await wp.data.select('core').getEntityRecords('taxonomy', 'post_tag', {per_page: 2, page: 2})

// No API call. Promise return array of 2 items
await wp.data.select('core').getEntityRecords('taxonomy', 'post_tag', {per_page: 2, page: 2})

image

@ramonjd
Copy link
Member Author

ramonjd commented Jun 18, 2024

@kozack-webspark Thanks for the report.

Not sure if this helps, but there is a 'resolveSelect` selector that will return the result of any resolved fetch promises:

await wp.data.resolveSelect('core').getEntityRecords('taxonomy', 'post_tag', {per_page: 2})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Core data /packages/core-data [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants