Skip to content

Support for writable signals with computed() #94

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

Closed
Syynth opened this issue Sep 7, 2022 · 5 comments
Closed

Support for writable signals with computed() #94

Syynth opened this issue Sep 7, 2022 · 5 comments

Comments

@Syynth
Copy link

Syynth commented Sep 7, 2022

Is it possible to support writes for signals returned via the computed function?
My intuition is that the computed function could simply take a second argument for the 'set' operation.

const user = new signal({ id: 1, name: 'foo' });
const name = computed(
  () => user.name,
  val => user.value = ({ ...user, name: value })
);

This has probably been considered already, but I'd be curious to hear if it's feasible or what the challenges would be.

@EthanStandel
Copy link

I could see this being useful. Alternatively, I just published a library that would allow you to use this kind of pattern, but with kind of the reverse mental model

@marvinhagemeister
Copy link
Member

I'm hesitant to turn computed signals into writable ones, but maybe I need to learn about the use cases or pattern this would enable. In the example provided I'm unsure what would happen if you update the signal via the second function and then an unrelated update to user.name from some other place?

If you're just looking for something more "store"-like than #4 is the issue to follow.

@marvinhagemeister
Copy link
Member

Closing this one, as it's the same topic as #4 . Let's continue the discussion about a store primitive over there.

@foxt
Copy link

foxt commented Mar 29, 2025

@marvinhagemeister Apologies for necro-ing (if you'd rather I'd be happy to open a new issue instead), but I'd argue it's very much not the same topic. (especially given that that issue seems to be of the opinion that deep writables are a good idea, which is not necessary or imo, actually a good idea)

For example, a writable computed is useful, because computeds return a derived value based on the state of other signals. It makes sense in some cases to have this derivation work in both directions, for example:

let heightCentimeters = signal(180);
let heightFeet = computed({
    get: () => heightCentimeters.value / 30.48,
    set: (value: number) => heightCentimeters.value = value * 30.48
});

heightFeet.value; // 5.91

heightFeet.value = 6;
heightCentimeters.value; // 182.88

@marvinhagemeister
Copy link
Member

marvinhagemeister commented Mar 30, 2025

@foxt Nothing prevents you from doing that today with a helper. I don't think it's something that belongs in the core library as it can lead to unexpected complexity when the manually set value should take precedence over the derived one vs not.

// Pseudo code
function mutableComputed<T>(fn: () => T) {
  const override = signal(undefined);
  const derived = computed(() => {
    return override.value !== undefined ? override.value : fn();
  });

  return {
    get value() {
      return derived.value
    },
    set value(v) {
      override.value = v
    }
  }
}

Or in other words: a writable computed is the same as a signal + a readonly computed.

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

4 participants