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

Using signals does not trigger re-render after updating the signal #120

Closed
motss opened this issue Sep 11, 2022 · 7 comments
Closed

Using signals does not trigger re-render after updating the signal #120

motss opened this issue Sep 11, 2022 · 7 comments

Comments

@motss
Copy link

motss commented Sep 11, 2022

Description

I'm trying to experiment with signals in Preact and found out that sometimes updating the value does not always trigger re-render when it should in a component. I would like to know if I'm using signals the correct way.

This is a minimal reduced test case to demonstrate the problem. The basic behavior is as follows:

  1. When there is no otpCode, hitting Enter in the Code input will trigger a countdown timer and you should see Resend in 00:10
  2. When there is otpCode, hitting Enter will evaluate fakeValid. When fakeValid is true, there will be no Resend in 00:10 and Send code button, and Code input will be in read-only mode.

Expected behavior

Re-render should happen after updating signal value, e.g. updating otpCode and otpStatus does not re-render.

Actual behavior

Re-render does not always happen after updating signal value, e.g. updating otpCode and otpStatus should re-render accordingly.

@mikerob215
Copy link

@motss The problem you're running into is that you are setting your signal value to an object and then updating the properties of that object, this won't cause a render because those properties are not themselves signals. For the signal to update you want to have an assignment to the signal's value property directly(link), that will trigger the setter, another option would be to use signals for those property values. The advantage of the latter approach is that you will then be able to pass a signal directly into the input(without .value) and take advantage of the optimization.

@motss
Copy link
Author

motss commented Sep 12, 2022

The advantage of the latter approach is that you will then be able to pass a signal directly into the input(without .value) and take advantage of the optimization.

@mikerob215 Do you mean value={otpCodeSignal}?

const otpCodeSignal = signal<string>('');

...

<input name="code" value={otpCodeSignal} />

Doing the above will not result in a TypeScript error. How do I resolve this?

typescript error when consuming signal directly

@marvinhagemeister
Copy link
Member

marvinhagemeister commented Sep 12, 2022

The JSX TS errors are tracked here: #106 . It's a typing issue with TS, but passing a signal into it works regardless.

@marvinhagemeister
Copy link
Member

Closing this issue, because like @mikerob215 noticed the provided example only tracks the whole state object. We didn't go with deep observability with signals, because it would end up with us having to wrap all built-in types (Array, TypedArray, etc) to observe mutations to them. The idea of the signals library is that we subscribe to them as late as possible, sometimes even as late as in the rendering itself. With deep observability that would be a lot harder to implement.

Looking at state in the provided example it looks like you want to be able to react to both the optStatus and name changing independently. That can be done by wrapping them in a signal:

- const state = signal<State>({ name: '', otpStatus: '' });
+ const state = { name: signal(''), otpStatus: signal('') };

@chenjiangui
Copy link

关闭这个问题,因为喜欢@mikerob215注意到提供的示例仅跟踪整个状态对象。我们没有对信号进行深度可观察性,因为最终我们不得不包装所有内置类型(Array,TypedArray等)来观察它们的突变。信号库的想法是我们尽可能晚地订阅它们,有时甚至晚于渲染本身。具有深度可观察性,这将更难实现。

@vue/reactivity is also headless signal lib, it's implement lazy deep observe, and it also can use in react or nodejs, and implement some EffectScope api. it's helpfull. https://github.com/vuejs/core/tree/main/packages/reactivity

@ShivamJoker
Copy link

- const state = signal<State>({ name: '', otpStatus: '' });
+ const state = { name: signal(''), otpStatus: signal('') };

this should be mentioned somewhere in the docs.

@geertjanb
Copy link

you can use signal without any problems.

ts: anyValue: Signal = this.state.anyValue;

html: {{ anyValue() }}

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

6 participants