solidjs / solid

A declarative, efficient, and flexible JavaScript library for building user interfaces.
https://solidjs.com
MIT License
32.51k stars 929 forks source link

createMemo should respect the equals value on its initial execution #2362

Open snnsnn opened 2 weeks ago

snnsnn commented 2 weeks ago

A memo accept an initial value and the equals property via the options object to exert finer control over its update logic. However it does not respect the equals property on its initial execution but it should for consistency.

For the following example, 'some value' should never be assigned to the memo as it is not a valid value.

import { createEffect, createSignal, createMemo } from 'solid-js';

const [preferences, setPreferences] = createSignal({
  lang: 'en', theme: 'some value', fontSize: 'large',
});

const theme = createMemo(() => preferences().theme, 'light', {
  equals: (prev, curr) => {
    if (prev === curr) return true;
    if (prev === 'dark' && curr === 'light') return false;
    if (prev === 'light' && curr === 'dark') return false;
    return true;
  }
});

createEffect(() => console.log(theme()));
atk commented 2 weeks ago

But equals by definition compares the last value to the next one. As there is no last value initially, you would have to guard your comparison against it being undefined.

In your case, a filter for invalid values should be done within the derivation, not the equals function.

snnsnn commented 2 weeks ago

I know how it works but what is the point of having an initial value if you don't utilize it, if you think about it, it is only logical to use the custom comparator function for the initial execution too. It better aligns with the behavior of a signal and it will reduce clutter as we can rely on the equals function to validate the next value, avoiding unnecessary conditionals.

atk commented 2 weeks ago

createMemo cannot know if you are intending to use the initial value or not.

snnsnn commented 2 weeks ago

createMemo cannot know if you are intending to use the initial value or not.

Please can you elaborate because I am not sure if I understand what do you mean by this sentence?

If current behaviour is OK, then what is the purpose of the initial value? More importantly what difference does it make if createMemo uses the equals value for the initial execution? Memo will be executed any way, equals controls if the returned value should replace the existing one, providing a consistent behavior.

atk commented 1 week ago

This was merely an answer to your statement that having an initial value was pointless if you're not using it. But that's merely your preference based on a single case.

In Solid, Ryan usually aims for the most helpful, predictable and performant behavior. Since an initial equality comparison without a previous value will be unhelpful except for very few edge cases, totally unexpected and easily provoking errors and provides the worse performance, he chose not to apply it.