marshallswain / feathers-pinia

Connect your Feathers API to the elegant data store for Vue
53 stars 22 forks source link

Live query not triggering re-render on data removal #116

Closed fhulst closed 1 year ago

fhulst commented 1 year ago

I'm using Feathers-Pinia 2.0.0-pre.14 in Vue script setup to render a reactive list with a live query:

<script setup lang="ts">
  const User = useUserModel()

  // Live query
  const { data, find } = User.useFind({query: {}})

  // Query server for initial data
  onBeforeMount(async () => {
    await find()
  })
</script>

<template>
  <ul>
    <li v-for="item in data">
      {{ item.name }}
    </li>
  </ul>
</template>

Creating an item works as expected: it gets created on the server and is immediately rendered on the client.

When removing an item, it gets removed on the server but the list is not re-rendered on the client. After a manual refresh the list gets re-rendered and is correct.

Observing through a second client, the item appears and disappears from the list immediately as expected. Thus the problem seems to be that the client that issues the removal is not re-rendering.

async function createAndRemove() {
  const user = User({ name: 'name', email: 'name@email.com' }).addToStore()
  await user.save()

  user.removeFromStore()
  await user.remove()

  await find().then((data) => { console.log('find: ', data) })
}

Also when calling find() after the removal, the promise returns with the actual data on the server, but yet the list is not re-rendered.

Am I missing something here?

ericuldall commented 1 year ago

I'm having similar issues with the useFind function. I can see the request property returned by useFind has the data, but that data does not persist into the data property returned by useFind. Really need to get this figured out as the useFind functionality is crucial for our application. @marshallswain Any thoughts on why this happens and how we can better debug it?

ericuldall commented 1 year ago

Mine seems to happen on first page load, but if I route to another page then come back it doesn't happen.

ericuldall commented 1 year ago

I keep trying different tests and there's doesn't seem to be any rhyme or reason. Sometimes the record makes it into the local storage, sometimes it does not. After adding a new item to a service my UI is not updated in realtime, even if the item was added to the store.

fhulst commented 1 year ago

@ericuldall Are you calling find()? The data property contains an empty array until the find() method returned by useFind() is called. In case you are using authentication, make sure to call find() at the right moment. Maybe try the following:

const authStore = useAuthStore()

watch(() => authStore.isAuthenticated, async (value) => {
  if (value) {
    await find()
  }
})

onBeforeMount(async () => {
  if (authStore.isAuthenticated) {
    await find()
  }
})

FYI, I do not get the inconsistent behavior that you describe. The UI updates in realtime when creating new items and editing existing items (using the clone-commit pattern). For me the problem is only that the UI consistently does not update after removing data items.

ericuldall commented 1 year ago

I've tried 2 ways, either using onServer: true which is supposed to immediately call find, or setting immediate: false and then calling find manually. Nonetheless it seems there is some bugs in the useFind behavior.

Another thing i'm not sure is/should be relevant. I'm still using feathers api v4 (i'm upgrading my client for a current project).

Can you share one of your model js/ts files for comparison?

ericuldall commented 1 year ago

Here's my sample code that does not work:

    const Task = useTaskModel();
    const activeParams = computed(() => {
        const query = { userId: props.userId, completed: false };
        return { query, onServer: true, immediate: false };
    });

    const completedParams = computed(() => {
        const query = { userId: props.userId, completed: true };
        return { query, onServer: true, immediate: false };
    });
    const { data: activeTasks, find: findActiveTasks, isPending: activePending } = Task.useFind(activeParams);
    const { data: completedTasks, find: findCompletedTasks, isPending: completedPending } = Task.useFind(completedParams);
    const addTask = async (description) => {
        const task = Task({
            description,
            userId: props.userId,
            completed: false
        }).addToStore();
        task.save();
    };
    const refreshTasks = () => {
        setTimeout(() => {
            findActiveTasks();
            findCompletedTasks();
        }, 10);
    };
    refreshTasks();

Initial tasks load, but calling addTask does not update my activeTasks Also, not seeing the new tasks added to my store

ericuldall commented 1 year ago

Also, regarding the part about authentication. I have my entire app waiting to load until authentication passes so once my views and components load it's already successfully authenticated.

<script setup>
import { LoadingApp } from '@/components/loading';
const authStore = useAuthStore();
</script>

<template>
  <RouterView v-if="authStore.isInitDone" />
  <LoadingApp v-else class="h-screen" />
</template>
ericuldall commented 1 year ago

So removing, onServer: true seems to fix my issue.

ericuldall commented 1 year ago

Another thing I notice. If I add to a model/store it does not update instances in another tab or browser. Using the socket server. I thought useFind was to be fully reactive from the socket updates, but maybe i'm missing something.

marshallswain commented 1 year ago

Thanks for reporting. I haven't had much time to triage issues. I'll look into this later this week.

marshallswain commented 1 year ago

@FrankvdHulst I found the problem causing the bug you found. Items definitely weren't being properly removed from the store after being removed from the server. This is fixed in feathers-pinia@2.0.0-pre.15.

marshallswain commented 1 year ago

@ericuldall, please let me know if you are still experiencing issues.

fhulst commented 1 year ago

Thank you! Your (one-character :P) fix works like a charm. I must say this live query functionality is pretty sweet.

marshallswain commented 1 year ago

Yeah, that was a facepalm moment when I saw the issue. It's funny, too, because I wrote over 160 additional unit tests for v2, and still didn't catch that part, because it needs integration tests.

I'm improved live queries quite a bit in version 3, which I started working on over the weekend. I almost have the server-side pagination working just as well as the local pagination, too. I'm excited to get it finished. V3 has all of the same features from v2, but gets rid of the required configuration steps. It's like 5 lines of code to get it up and going. It also moves all data fetching to the Feathers Client with implicit data modeling.