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

Deleting items in a store Observable<Record<string, Item>> does not update derived lists () => Object.values(state$.items) correctly. #424

Open
cpakken opened this issue Dec 29, 2024 · 1 comment

Comments

@cpakken
Copy link

cpakken commented Dec 29, 2024

Please refer to the minimal reproducible examples

cpakken/legend-computed-lists-issue

https://stackblitz.com/github/cpakken/legend-computed-lists-issue

  • Deleting items in a store Observable<Record<string, Item>> does not update derived lists () => Object.values(state$.items) correctly.

  • I suspect there is a probably reactively updating the indexes of derived arrays from Object.values()

  • Adding and deleting items from the END of list seems to be fine.

  • Problems when deleting items that require changing indexes will result in issues.

    • Example will show deleting item from the first in list..
    • if item.delete() is called in a batch with itemList.peek() (or itemList.get()) afterwords, it fixes SOME issues.
  • Should work without .peek() or .get() on the computed list

const getNumFromId = (id?: string) => (id ? parseInt(id.split('_')[1]) : 0)

export const getRandomNum = () => Math.floor(Math.random() * 10 ** 5)

const createItemEntry = (id: number) =>
  [`ID_${id}`, { id: `ID_${id}`, value: getRandomNum() }] as const

export const state$ = observable({
  //Items Store
  items: Object.fromEntries(Array.from({ length: 5 }, (_, i) => createItemEntry(i + 1))),
  /*
  items : { 
    'ID_1': { id: 'ID_1', value: 12345 },
    'ID_2': { id: 'ID_2', value: 12345 },
    'ID_3': { id: 'ID_3', value: 12345 },
    'ID_4': { id: 'ID_4', value: 12345 },
    'ID_5': { id: 'ID_5', value: 12345 } 
    }
  */

  //Item List
  itemList: () => Object.values(state$.items),
  /*
  itemList : [
    { id: 'ID_1', value: 12345 },
    { id: 'ID_2', value: 12345 },
    { id: 'ID_3', value: 12345 },
    { id: 'ID_4', value: 12345 },
    { id: 'ID_5', value: 12345 } 
  ]
  */

  //Derived List
  itemDerivedList: () => state$.itemList.map(itemMapper),
  /*
  itemDerivedList : [
    { value: 'ID_1_12345' },
    { value: 'ID_2_12345' },
    { value: 'ID_3_12345' },
    { value: 'ID_4_12345' },
    { value: 'ID_5_12345' } 
  ]
  */
})

const itemMapper = weakMemo(({ id, value }: Observable<{ id: string; value: number }>) => {
  console.log('SHOULD BE MEMOIZED AND CREATED ONCE', id.get())
  return { value: () => id.get() + '_' + value.get() }
})
@cpakken
Copy link
Author

cpakken commented Dec 30, 2024

Updated the example with filteredList and sortedList

  //!NOTE When items are deleted (from first in list), the fitlered result is wrong. Index are wrong
  filteredList: () => state$.itemList.filter((item) => item.value.get() > 40000),

  //IF DELETED ITEMS ORDERED FIRST IN LIST, THEN TOGGLE RANDOMIZE TO SEE SORTED (TAB WILL FREEZE)
  sortedList: () => [...state$.itemList].sort((a, b) => a.value.get() - b.value.get())

These computed lists will generally work when items are added to the end of the array list or deleted from the array list but will have problems when items are deleted that require index change. For example, when deleting the first item from the list,

Filtered list will not show the correct results (internal indexes out of order). When rendering sortedList deleting items out of order will freeze the tab.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant