-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Make export const
a way to define constant unreactive props
#5572
Comments
So, you're suggesting that
|
My suggestion would be that the original component is destroyed and a new one is created in its place with the new const value. In support of the proposal, i would suggest that the lack of this feature is the cause of some bugs. Im on a phone so providing an example is hard right now. Let me know if I am being unclear and I will provide an example when I am at a computer. |
Here is an example, with a workaround: Ideally we could come up with a way to automatically produce an equivalent of the workaround. |
That behavior would be extremely surprising and unintuitive. I think |
I think this is a great idea. Have had many similar cases myself, this would be really useful. |
As a newcomer to Svelte, not having a way to define constant props (with a supported default/fallback value) feels like a risk to the reliability of data passed between components. In situations where props are passed down a few layers, if one of those prop values changes along the way, the app may not operate as expected, and this would not be considered a bug with Svelte. That said — I think adding support for immutable props would be a huge advantage for all Svelte developers. export const importedValue = 5;
// │ │ └────┐ │
// prop immutable variable default (fallback) value |
I'm also a newcomer to svelte. One problem when doing this is that I also have to add a default value, so this is invalid syntax: <script>
// ColorOption.svelte
export const name: StyleOption;
</script> Here's another workaround that seems less unintuitive than using <script>
$: {
name
throw ReferenceError("name is immutable")
}
</script> |
Svelte currently supports input/output and output props (see <script>
// 1) input/output prop - supports input (a={...}) and input/output (bind:a={...}) syntax
export let a;
// 2) output props - can be accessed via bind:this={self}/self.b and input/output (bind:b={...}) syntax
export const b = /* ... */ 0;
export function c() { /* ... */ };
// 3) non-reactive code - code may be based on input props, but this code will not be re-run when they are updated
/* ... */
// 4) reactive code - code here will be re-un if any of the referenced properties are updated
$: { /* ... */ }
</script> I am finding that this missing feature leads to components being defined with syntax that suggests mutable props but whos implementations expect those inputs to remain constant. Whilst there are exotic cases where it makes sense for non-reactive code to reference the initial values of mutable props, syntax for an immutable propIf immutable input props were to be added, what would the syntax be? Some suggestions:
changing an immutable propIf immutable input props were to be added, what would happen if a new value was assigned to them? Possible solutions:
|
(FYI, I was @intelcentre - work account) In my experience, writing complex components where all inputs are reactive can easily get quite complex. Another parallel would be how languages such as C# allow classes to have readonly member variables. If you think of components as class instances, readonly member variables would be a direct parallel to what is being discussed here. |
I also find that exported const variable, but still assigned by parents would be a really great addition to Svelte. The only alternative is currently to add Typescript'
I think that a sensible implementation would rather fail compilation of the given example, and only allow constants to be passed to exported constants. So given: // Component.svelte
export const answer Only this would be possible: // OK
<Component answer=42 />
// OK
<script> const answer = 42 </script>
<Component { answer }/> And this would fail: // Error: assigning mutable variable `answer` to const export
<script> let answer = 42 </script>
<Component { answer }/> As nice as it would be, it wouldn't even be a breaking change: |
Also new to Svelte, so forgive me if I'm stating something incorrect. Allowing a way to define a constant prop could also circumvent the issue when, in my case, creating a single TextInput.svelte <script lang="ts">
export let type: 'date' | 'email' | 'month' | 'text' = 'text'; // etc etc
export let value;
</script>
<input {type} bind:value={value} /> Which could then elegantly be reused similar to vanilla HTML inputs by setting the type property. I initially figured I could fix the error by making it a const, but of course that means the parent component cannot set the prop on initialization / creation of the component. |
With Svelte 5 on the horizon things are shifting more towards the runtime, so the code savings for having this kind of "set once" property are negligible, both bundle-size-wise and performace-wise, therefore closing. |
@dummdidumm I've been watching this issue for a while now. I would counter the closure reason, as this issue is critical to DX. Svelte still offers no way to set up nonreactive props. This issue solves that. |
Why is that important, other than theoretical bundle size and performance savings? |
@dummdidumm For the same reason it's important to have both In JS, we can theoretically use In this case, you would pass in a value for a |
In the case you need this it's very easy to do yourself: // Svelte 4
export let fixed;
export let dynamic;
const _fixed = fixed;
// Svelte 5 runes
let { fixed, dynamic } = $props();
const _fixed = fixed; // use _fixed everywhere else |
This does not prevent Having a way to explicitly declare that a property cannot and shouldn't be updated seems like a reasonable use case, considering that JS itself has |
I agree with @Oreilles that this actually feels like a mistake and recipe for disaster in both syntaxes, with the traditional approach and with the new rune-based approach. |
This is a documentation problem. The property name and its documentation should suggest that this is static. If there was a separate concept built-in to Svelte, you wouldn't see if the property is static from the other side either.
When a component developer opts for a static property (which is a very rare case; I still haven't heard a compelling use case) they are likely ok with the additional complexity
|
Why should we have to add documentation stating that something should not be reassigned, without any guarantee or protection against someone doing it, when JS already has a way to define constants and natively prevent it ? This seems to go against the very spirit of Svelte.
There are many cases where it would make no sense that a property changed during a component lifecycle, and where you'd want that property to be declared as
Shallow immutability is not a new concept since as you state, that's already what |
Maybe I'm stupid and don't get it, but how do you think a const property is associated with a JS concept? I see svelte components as functions or constructors, none of which can have const arguments in JS. Const in JS means that the assignment is constant, you can't reassign anything to it. I would understand it to mean that you can't pass the property to the component from the outside (which would make such a public property pointless in the first place). When you pass a constant (with a primitive value like the string in your example) to a function in JS, the constant is passed as a value, not a reference, and if you change it later, the function body will never know. This is the same as the workaround dummdidumm posted. I stumbled across this issue when I was researching whether it would make sense to destructure props as const (svelte 5). I would really like to understand what specific use case you see for public constant properties. |
It is often the case that component props happen to be either by intent or de facto constant and unreactive
Unfortunately Svelte does not provide a way to define unreactive props, in doing so it outputs a substantial amount of superfluous code, makes components less shareable , and misses an otherwise fantastic opportunity for the compiler to identify "unreactive", so called pure components on its own to optimize their output accordingly
While Svelte features the ability to define props using
export const
, props defined by that syntax can only be derived from other props, and cannot be set directly.Described in the documentation as a way to define "readonly" props, it mistakenly draws parallels for some of us to Typescript's
readonly
class property modifier which, contrary to Svelte's const props, defines readonly properties that in fact can be set directly on initFor those reasons, and because it would greatly enhance an otherwise very rarely used feature, I believe that there is a great case to make for const props to be settable on init
This proposed change asserts for the following to render
42
Most scenarios where this change would qualify as breaking also qualifies as an unintended use case as values passed to const props currently throw
unknown prop
dev warnings. With that said this is still a breaking change in cases whereexport const
is used in combination with$$props
, as the latter suppresses unknown props dev warnings.I do not expect this to be implemented as it is technically breaking, but considering the value it could hypothetically add to the framework I still think it's worth putting a proposal out there
Possibly related #5183
The text was updated successfully, but these errors were encountered: