Skip to content

2.0.0-rc.1 | signal source function revaluates when derived from a component prop - on component cleanup #3024

Description

@mizulu

Describe the bug

In the reproduction, we can see that after a cleanup of the component
the signal value logs the value initially passed to prop.val
if we enable the "eval" log we will also see it evaluation on the flush of the cleanup.

the question is why will a cleanup trigger reevaluation of the signal source function
if the prop value never changed, in that process.

Your Example Website or App

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

Steps to Reproduce the Bug or Issue

see reproduction code instructions included

Expected behavior

signal created in the child component should retain the last value it was set with
on component cleanup

there might be code that will run after cleanup that might still need the last value set
and this creates an unexpected behavior for not apparent reason.

Screenshots or Videos

No response

Platform

.

Additional context

import { render } from '@solidjs/web';
import { createSignal, onSettled, flush, Show, refresh } from 'solid-js';


function Value(props) {
  // signal with function 
  const [sA, setA] = createSignal(() => {
    //console.log("eval")
    return props.val
  })

  // signal with value 
  const [sB, setB] = createSignal(111)
  return <>
    <div>
      <button
        class="bg-purple-500 hover:bg-purple-700 text-white font-bold py-1 px-2 rounded" onClick={() => {
          setA(333)
          flush()
          console.log(sA()) // 333
          props.inc()      // inc to toggle off
          flush()          // flush 
          console.log(sA()) // 0

        }}>
        A {sA()}
      </button>
    </div>
    <div>
      <button class="bg-orange-500 hover:bg-orange-700 text-white font-bold py-1 px-2 rounded" onClick={() => {
        setB(666)
        flush()
        console.log(sB()) // 666
        props.inc()      // inc to toggle off
        flush()          // flush 
        console.log(sB()) // 666

      }}>
        B {sA()}
      </button>
    </div>
  </>
}

const preMessage = `1. click A 
  logs: 
    333
    0     <- reverted to props.val  due to reevaluation 
2. Click "Toggle On" 
2.1 click B
  logs: 
    666
    666
    `

export default function App() {
  const [count, setCount] = createSignal(0);
  return (
    <div class="p-2">
      <pre class="text-sm">
        {preMessage}
      </pre>
      <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" onClick={() => setCount(count() + 1)}>
        {count() % 2 == 0 ? "toggle off" : "toggle on"}
      </button>
      <Show when={count() % 2 === 0}>
        {() => {
          return <Value inc={() => setCount(v => v + 1)} val={0}></Value>
        }}
      </Show>
    </div>
  );
}


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

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