preactjs / signals

Manage state with style in every framework
https://preactjs.com/blog/introducing-signals/
MIT License
3.83k stars 95 forks source link

[Vite] Component does not keep track of Signal value when updated #357

Open 9Morello opened 1 year ago

9Morello commented 1 year ago

I have tested this using Vite's preact-ts template. Using the useState hook keeps the state after the component gets reloaded because of a change:

export function App() {
  const [count, setCount] = useState(0)

  return (
    <>
      <div class="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/app.tsx</code> and save to test HMR
        </p>
      </div>
    </>
  )
}

With the above, I can change the text inside the p tag, or change the counter display to count * 2, and count's value stays the same as the component reloads.

However, using the same component with the useSignal hook, it doesn't work:

export function App() {
  const count = useSignal(0)

  return (
    <>
      <div class="card">
        <button onClick={() => count.value++}>
          count is {count}
        </button>
        <p>
          Edit <code>src/app.tsx</code> and save to test HMR
        </p>
      </div>
    </>
  )
}

Any change to text or to the function inside the onClick parameter resets count to 0. Is there any way to avoid this? Am I misunderstanding something? Sorry for the trouble.

rschristian commented 1 year ago

when updated

Are you referring to HMR? Might be an issue for Prefresh.

Edit: Hmm, looks like it should be supported, per https://github.com/preactjs/preset-vite/pull/58

9Morello commented 1 year ago

@rschristian Hello! Yes, I am referring to HMR. Do you think I should recreate this issue on the Prefresh repo?

Edit: I've just tested this with React instead of Preact and the same issue shows up. Changing other parts of the JSX (such as the text inside the p tag) causes count to go back to its default value, and if you use the useState hook instead, the value is kept after a hot reload as expected.

rschristian commented 1 year ago

Do you think I should recreate this issue on the Prefresh repo?

Can just CC @JoviDeCroock here, he would know best I believe. I don't know where we broke support, assuming it was working once.

I've just tested this with React instead of Preact and the same issue shows up.

React is a different beast entirely. Given the relationship of an external org trying to patch React to support signals and its ergonomics, I'm not sure HMR support in React is something that can be hoped for.

jesseagleboy commented 1 year ago

@9Morello I've ran into this issue too but I was thinking that was the norm if the computed values weren't wrapped in a useComputed hook. If I use a useSignal, I wrap the return value using that signal's value in a useComputed or I create a signal outside of the component function and use a return statement in the useEffect of the component to clean up (reset) the signal's value on un-mounting. I've done this for a couple of components already and I don't think I've ran into any optimization bugs.