aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.43k stars 2.13k forks source link

observeQuery provides outdated values #11101

Closed VadimDubovoy closed 1 year ago

VadimDubovoy commented 1 year ago

Before opening, please confirm:

JavaScript Framework

React

Amplify APIs

DataStore

Amplify Categories

Not applicable

Environment information

``` # Put output below this line System: OS: macOS 13.2 CPU: (8) arm64 Apple M1 Memory: 458.83 MB / 16.00 GB Shell: 5.8.1 - /bin/zsh Binaries: Node: 18.12.1 - /usr/local/bin/node npm: 9.1.1 - ~/.npm-global/bin/npm Browsers: Chrome: 111.0.5563.64 Firefox: 107.0.1 Safari: 16.3 npmPackages: @testing-library/jest-dom: ^5.16.5 => 5.16.5 @testing-library/react: ^14.0.0 => 14.0.0 @testing-library/user-event: ^14.4.3 => 14.4.3 aws-amplify: ^5.0.16 => 5.0.20 color-convert: ^2.0.1 => 2.0.1 (1.9.3) dateformat: ^5.0.3 => 5.0.3 jotai: ^2.0.2 => 2.0.3 lodash: ^4.17.21 => 4.17.21 pptxgenjs: ^3.11.0 => 3.11.0 rc-input-number: ^7.4.0 => 7.4.2 react: ^18.2.0 => 18.2.0 react-color: ^2.19.3 => 2.19.3 react-datepicker: ^4.10.0 => 4.10.0 react-dom: ^18.2.0 => 18.2.0 react-helmet: ^6.1.0 => 6.1.0 react-router-dom: ^6.8.2 => 6.9.0 react-scripts: 5.0.1 => 5.0.1 react-select: ^5.7.0 => 5.7.0 uuid: ^9.0.0 => 9.0.0 (3.4.0, 8.3.2) web-vitals: ^3.1.1 => 3.3.0 npmGlobalPackages: @aws-amplify/cli: 10.8.0 @sanity/cli: 2.30.2 gatsby-cli: 4.18.1 npm-check-updates: 16.7.12 npm: 9.1.1 skpm: 1.3.2 ```

Describe the bug

I have a list of items queried by observeQuery and stored in state. On the same page I have an input to rename one of the items. Every time I rename an item, it gives me a new array of items, but this items have new names only after the first change. Any following changes won't be reflected in the items I got from observer, unless I resubscribe.

Expected behavior

Receive fresh fully updated items after any number of changes with no need to unsubscribe/subscribe.

Reproduction steps

  1. Define state to store query results into;
  2. Subscribe to observeQuery inside useEffect with empty array of dependencies to avoid re-subscriptions;
  3. Make at lease two updates (query -> save -> copyOf) of the items;
  4. Review the items received from the observer.

Code Snippet

Setup observeQuery:

const [ list, setList ] = useState([]);
useEffect(() => {
  const sub = DataStore.observeQuery( Post, Predicates.ALL, {
    sort: s => s.updatedAt(SortDirection.DESCENDING)
  }).subscribe( 
    ({items}) => setList(items);
  );
  return () => sub.unsubscribe();
}, [])

Update a name:

const onSubmit = async (e) => {
  e.preventDefault();
  const data = new FormData(e.target);
  const title = data.get('title');
  const original = await DataStore.query( Post, id );
  await DataStore.save(
    Post.copyOf( original, updated => {
      updated.title = title;
    })
  )
}

Try to change name at least two times.

Log output

``` // Put your logs below this line ```

aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

e-simpson commented 1 year ago

It seems SortDirection.DESCENDING is currently broken in observeQuery? Experiencing this. SortDirection.ASCENDING works just fine.

VadimDubovoy commented 1 year ago

It seems SortDirection.DESCENDING is currently broken in observeQuery? Experiencing this. SortDirection.ASCENDING works just fine.

Sorting works fine in my case. The last renamed item goes first despite the fact I receive outdated data (updatedAt incl.) from observeQuery.

iartemiev commented 1 year ago

Thanks for opening the issue @VadimDubovoy. I was able to repro following the steps you provided. Labeling this as a bug. The team will work on patching it.

As @e-simpson mentioned above, the stale results are only emitted when specifying SortDirection.DESCENDING, so you can use one of the following temporary workarounds in the meantime:

  1. Omit the sort param and manually sort the results in the observeQuery callback before applying them to your UI state

    const sub = DataStore.observeQuery(Post).subscribe(({ items }) => {
    setList(
    items.sort((a, b) =>
      a.updatedAt < b.updatedAt ? 1 : a.updatedAt > b.updatedAt ? -1 : 0
    )
    );
    });

    OR

  2. Use observe or observeQuery as a trigger to perform a sorted query

    
    useEffect(() => {
    const sub = DataStore.observe(Post).subscribe(() => getPosts());
    }, []);

async function getPosts() { const results = await DataStore.query(Post, Predicates.ALL, { sort: (s) => s.updatedAt(SortDirection.DESCENDING), }); setList(results); }

VadimDubovoy commented 1 year ago

Thanks for reply @iartemiev. Turns out I didn't understand @e-simpson 's comment. The workarounds work as expected. Hope to see the bug fixed soon.

iartemiev commented 1 year ago

We released a fix for this issue in aws-amplify@5.0.22