Skip to content

2.0.0-beta.26 | optimistic store unexpected pending state for store or dependency, while having an optimistic override #2951

Description

@mizulu

Describe the bug

There are 2 main Issues

  1. the unexpected pending state of the store while it has an optimistic override
    both case1 and case2 of the repro covers this.

  2. In case 2 of the reproduction, it shows few issues
    a. the count() entering the pending state on the 2nd quick consecutive click
    b. the 2nd optimistic write instead of having 2 new items added, the item from the first click is getting overridden , however if you manage to click more than 2 times quickly, say 3 quick clicks or more
    from the 3rd click you will see new items being added optimistically.
    when settle we get the missing first item that was overridden by the 2nd click


start playground wait until Items is loaded

repro steps for the pending case, but since there are multiple issues here
you can see the video for the incorrect override state.

Case1:

  1. click the increment button increment once
    renders:
    s_not_pending
    count_not_pending
    Case2:
  2. click the increment button 2 times quickly
    on the first click
    renders:
    s_pending <----
    count_not_pending
    on the 2nd click
    renders:
    s_pending <----
    count_pending <----

In both cases
the button click increment the count() and should make
and reruns the store function, which should be pending
until data() is resolved

however we see that
store.items is pending even though we have an optimistic write
and on the 2nd call we also get count() back into pending

it is not clear why count is not pending on first click
but then is pending on the 2nd click ( case 2)

also why s.items is pending in the first and 2nd click
in both cases ( case 1 and case 2 )
it was assumed that an optimistic write to a store should
take it out of pending due to the "override"

Your Example Website or App

https://s.olid.uk/id/cBNfYlwqQxyf0NyEvb62DQ

Steps to Reproduce the Bug or Issue

import { render } from '@solidjs/web';
import { createSignal, createOptimisticStore, Loading, isPending } from 'solid-js';

const time = async (ms = 1000) => new Promise(r => setTimeout(r, ms))




export default function App() {

  const [count, setCount] = createSignal(0);


  // static data source
  let _data = [{ id: 1, name: "A" }];


  // no reactiviy deps in this function 
  async function data() {
    console.log("data function...")

    await time() // small delay

    console.log("/data function...")
    return {
      items: [
        ..._data
      ]
    }
  }


  // store has count() and data() as deps
  const [s, setStore] = createOptimisticStore(() => {
    console.log("Store Function")

    count() // add count as dep
    return data()
  }, { items: [] })





  // simulate new data in static source.
  function pushNewBackEnd() {
    const item = { id: _data.length + 1, name: "U" + (_data.length + 1) }
    _data.push(item)

    // this starts an optimistic override
    // when count is incrmented with the button click 
    // count does not show pending, because this takes it out of the transition 
    // however the store.items still shows as pending 
    // while the data() is resolved.
    // without this optimistic write both store.items and count 
    // show as pending. 
    setStore(s => { s.items.push({ ...item, ...{name: item.name+"*"}, id:item.id+"*" }) })

  }
  return (
    <div class="p-2">
      <Loading>
        <div>{isPending(() => s.items) ? <b>s_pending</b> : "s_not_pending"}</div>
        <div>{isPending(count) ? <b>count_pending</b> : "count_not_pending"}</div>
      </Loading>

      <div>
        Increment To trigger New Item <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" onClick={() => {
          setCount(count() + 1) // trigger deps change in 
          pushNewBackEnd() // push new item to static source
                           // and do optimistic update 

        }}>
          Increment: {count()}
        </button>

      </div>



      <div style="font-size:24px;">Items:</div>
      <Loading fallback={"Loading..."}>
        {s.items.map((v) => {
          return <div>Id: {v.id}  Name:{v.name}</div>
        })}
      </Loading>
    </div>
  );
}


if (typeof document !== 'undefined') {
  render(() => <App />, document.getElementById('root')!);
}

Expected behavior

it might be expected that an optimistic override
to a pending store, will take it out of the transition
similar to how count is first not part of the transition

so in both case1 and case2 it might be expected
that count and store.items will not show pending due to the optimistic store right.
but it is possible that because the optimistic store is that one holding the transition
and also the one that has the optimistic override
the system struggles to manage the pending state ( just an assumption )

Screenshots or Videos

Image

Platform

.

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions