Skip to content
This repository was archived by the owner on Oct 16, 2024. It is now read-only.

Computed value is not recomputed after dependencies change #219

Closed
leopf opened this issue Jan 24, 2022 · 4 comments
Closed

Computed value is not recomputed after dependencies change #219

leopf opened this issue Jan 24, 2022 · 4 comments
Labels
@agile-ts/core Related to the @agile-ts/core package bug Something isn't working

Comments

@leopf
Copy link

leopf commented Jan 24, 2022

🐛 Bug report

I have a problem with not updating computed values. I am using a demo API to download and insert users into a collection. I want to use a computed value to get a user from this collection based on a user id, which is defined in a state. The first compute works with the default user id, but after updating the user id the value is not recomputed. I took a look at the deps prop and found all the necessary observers with the correct values, though the value of the computed user was incorrect.

The first compute only works if I define the computed value after inserting the users into the collection, otherwise this computed value is stuck on undefined.

🤖 Current Behavior

const data: any[] = await fetch('https://jsonplaceholder.typicode.com/users').then(res => res.json());

const userCollection = createCollection();
const selectedUserId = createState(1);
selectedUserId.watch(() => console.log("---- new selected user id!"));

for (const item of data) {
    userCollection.collect(item);
}

const selectedUser = createComputed(() => {
    return userCollection.getItemValue(selectedUserId.value);
});

console.log("auto:", selectedUser.value);
selectedUserId.set(2);
console.log("manual:", userCollection.getItemValue(selectedUserId.value));
console.log("auto:", selectedUser.value);
console.log(selectedUser.deps);

output:

auto: {
  id: 1,
  name: 'Leanne Graham',
  username: 'Bret',
  email: 'Sincere@april.biz',
  address: {
    street: 'Kulas Light',
    suite: 'Apt. 556',
    city: 'Gwenborough',
    zipcode: '92998-3874',
    geo: { lat: '-37.3159', lng: '81.1496' }
  },
  phone: '1-770-736-8031 x56442',
  website: 'hildegard.org',
  company: {
    name: 'Romaguera-Crona',
    catchPhrase: 'Multi-layered client-server neural-net',
    bs: 'harness real-time e-markets'
  }
}
---- new selected user id!
manual: {
  id: 2,
  name: 'Ervin Howell',
  username: 'Antonette',
  email: 'Shanna@melissa.tv',
  address: {
    street: 'Victor Plains',
    suite: 'Suite 879',
    city: 'Wisokyburgh',
    zipcode: '90566-7771',
    geo: { lat: '-43.9509', lng: '-34.4618' }
  },
  phone: '010-692-6593 x09125',
  website: 'anastasia.net',
  company: {
    name: 'Deckow-Crist',
    catchPhrase: 'Proactive didactic contingency',
    bs: 'synergize scalable supply-chains'
  }
}
auto: {
  id: 1,
  name: 'Leanne Graham',
  username: 'Bret',
  email: 'Sincere@april.biz',
  address: {
    street: 'Kulas Light',
    suite: 'Apt. 556',
    city: 'Gwenborough',
    zipcode: '92998-3874',
    geo: { lat: '-37.3159', lng: '81.1496' }
  },
  phone: '1-770-736-8031 x56442',
  website: 'hildegard.org',
  company: {
    name: 'Romaguera-Crona',
    catchPhrase: 'Multi-layered client-server neural-net',
    bs: 'harness real-time e-markets'
  }
}
Set(2) {
  StateObserver {
    agileInstance: [Function (anonymous)],
    key: undefined,
    dependents: Set(1) { [StateObserver] },
    subscribedTo: Set(0) {},
    value: 2,
    previousValue: 1,
    state: [Function (anonymous)],
    nextStateValue: 2
  },
  StateObserver {
    agileInstance: [Function (anonymous)],
    key: 2,
    dependents: Set(1) { [StateObserver] },
    subscribedTo: Set(0) {},
    value: {
      id: 2,
      name: 'Ervin Howell',
      username: 'Antonette',
      email: 'Shanna@melissa.tv',
      address: [Object],
      phone: '010-692-6593 x09125',
      website: 'anastasia.net',
      company: [Object]
    },
    previousValue: null,
    state: [Function (anonymous)],
    nextStateValue: {
      id: 2,
      name: 'Ervin Howell',
      username: 'Antonette',
      email: 'Shanna@melissa.tv',
      address: [Object],
      phone: '010-692-6593 x09125',
      website: 'anastasia.net',
      company: [Object]
    }
  }
}

🎯 Expected behavior

I would expect this to work, as defined in the docs.

const MY_COMPUTED = createComputed(() => {
    const user = USERS.getItemValue(CURRENT_USER_ID.value);
    return `My name is '${user?.name} and I am ${user?.age} years old.`;
});
MY_COMPUTED.value; // Returns "My name is 'hans' and I am 10 years old."
USERS.update(CURRENT_USER_ID.value, {name: 'jeff'})
MY_COMPUTED.value; // Returns "My name is 'jeff' and I am 10 years old." 

📄 Reproducible example

I created a simple main.ts file and ran it with ts-node.

import { createState, createCollection, createComputed } from "@agile-ts/core";
import fetch from 'cross-fetch';

async function init() {
    const data: any[] = await fetch('https://jsonplaceholder.typicode.com/users').then(res => res.json());

    const userCollection = createCollection();
    const selectedUserId = createState(1);
    selectedUserId.watch(() => console.log("---- new selected user id!"));

    for (const item of data) {
        userCollection.collect(item);
    }

    const selectedUser = createComputed(() => {
        return userCollection.getItemValue(selectedUserId.value);
    });

    console.log("auto:", selectedUser.value);
    selectedUserId.set(2);
    console.log("manual:", userCollection.getItemValue(selectedUserId.value));
    console.log("auto:", selectedUser.value);
    console.log(selectedUser.deps);
}

init();

💡 Suggested solution(s)

➕ Additional notes

💻 Your environment

Software Version(s)
TypeScript v4.5.4
npm/Yarn v8.3.2
NodeJs v14.18.2
@agile-ts/core v0.2.8
@agile-ts/react N/A
@agile-ts/api N/A
@agile-ts/multieditor N/A
ts-node v10.4.0
@bennobuilder
Copy link
Contributor

Thanks for reporting this issue @leopf ;D
It looks like that the computed value isn't ingested into the runtime correctly.
The compute() method is called as expected, and returns the correct value (see red marked part).
However, this returned value doesn't seem to get applied to the State.

image
https://codesandbox.io/s/issue-219-ufcck?file=/src/main.js

I'll dig into your issue this evening and keep you updated.

Thanks ;D


  • You can also use Selectors to select a specific State in a Collection.

@leopf
Copy link
Author

leopf commented Jan 24, 2022

Thanks for the quick response! I did some digging as well, and it seems like the computed value is updated asynchronously. I added a sideeffect to test this:

...
const selectedUser = createComputed(() => {
    return userCollection.getItemValue(selectedUserId.value);
});

selectedUser.addSideEffect("somerandomkey", (instance) => console.log("NEW SELECTED USER:", instance.value), { weight: 0 });
...

The new output is the same except after the already posted output it outputs the new value for the computed instance.

NEW SELECTED USER: {
  id: 2,
  name: 'Ervin Howell',
  username: 'Antonette',
  email: 'Shanna@melissa.tv',
  address: {
    street: 'Victor Plains',
    suite: 'Suite 879',
    city: 'Wisokyburgh',
    zipcode: '90566-7771',
    geo: { lat: '-43.9509', lng: '-34.4618' }
  },
  phone: '010-692-6593 x09125',
  website: 'anastasia.net',
  company: {
    name: 'Deckow-Crist',
    catchPhrase: 'Proactive didactic contingency',
    bs: 'synergize scalable supply-chains'
  }
}

This would make sense, since the compute function within the Computed instance is asynchronous. For this to work, it might be necessary to differentiate between async and sync compute functions under the hood.

If my suspicion proves correct, I will follow up with a PR.

@bennobuilder
Copy link
Contributor

Yeah, you are right 👍
The fact that the wrapper compute method itself is async seems to create this issue.
Adding a small timeout shortly after mutating the userId seems to give the compute() method
enough time to compute itself asynchronously, as the wrapper method is async.

See code sandbox: https://codesandbox.io/s/issue-219-ufcck?file=/src/main.js

@bennobuilder bennobuilder added @agile-ts/core Related to the @agile-ts/core package bug Something isn't working labels Jan 24, 2022
@bennobuilder
Copy link
Contributor

bennobuilder commented Sep 4, 2022

fixed in #222

# for free to subscribe to this conversation on GitHub. Already have an account? #.
Labels
@agile-ts/core Related to the @agile-ts/core package bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants