Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

A completely different approach to defining components #1826

Copy link
Copy link
Closed
@Rich-Harris

Description

@Rich-Harris
Issue body actions

Ok, brain dump time.

We often get questions in the chatroom about why you can't use methods in templates, and that sort of thing. And React people often look at code like this...

<Nested foo={bar}/>

<script>
  import Nested from './Nested.html';

  export default {
    components: { Nested },

    data: () => ({
      bar: 1
    })
  };
</script>

...and ask 'why do you need to register the component? We don't have that problem because our apps are Just JavaScript™️'. And while there are good technical reasons for both of those things, in the context of the current design, the truth is they have a point.

I've occasionally wondered if there's a way to have the best of both worlds. It boils down to the template being able to access variables that are in scope in the <script>:

<script>
  import Nested from './Nested.html';
  const bar = 1;
</script>

<Nested foo={bar}/>

The issue, of course, is that bar is no longer reactive — there's no way to say 'this value has changed, please update the child component'.


Last week, the React team introduced hooks. If you haven't watched Sophie and Dan's talk, I do recommend it.

I've been slightly ambivalent about hooks — for the most part, they solve problems that are specific to React. But they do make me wonder if there's a way to solve the worst ergonomic drawbacks of Svelte's approach.


Here's a version of the example above using the useState hook to make bar reactive:

<script>
  import { useState } from 'svelte/hooks';
  import Nested from './Nested.html';

  const [bar, setBar] = useState(1);
</script>

<Nested foo={bar}/>
<button on:click="setBar(bar + 1)">increment</button>

I had a go at rewriting a few more examples in this style to get a sense of what it would entail. I've been fairly pleasantly surprised; in many cases no changes are necessary (because the components only contain markup and possibly styles), and in the cases where changes are necessary, the code gets cleaner and more concise.

What I haven't done is figure out exactly what this would mean for the compiler. Svelte's whole deal is that it avoids doing as much work as possible, and there are two main components to that — avoiding touching the DOM, and not giving the user a place to accidentally do unnecessary and expensive computation. This means a) knowing which values could have changed, and b) not having a big ol' render function. This approach clearly makes that harder. Impossible? Not sure.

Things I'm thinking about, in no particular order:

  • setFoo(...); setBar(...) instead of set({ foo: 1, bar: 2 }) means you really need to batch the work up, which sort of forces us into an async paradigm. Maybe that's ok? Not sure
  • There'd need to be a way to access the component's props inside the <script> — at least in useComputed (React has useMemo for a similar purpose) and the equivalent of useEffect
  • We've been encountering some tricky bugs recently around the order of oncreate, ondestroy etc, particularly when there are bindings or immediate set(...) calls. This feels like it could be a way to side-step those entirely
  • Need to consider the runtime complexity this would add
  • Not sure how this could work with standalone components. Hooks work by maintaining a central registry, which doesn't immediately make sense for standalone things
  • There's no obvious way to do inter-component bindings. Maybe export { thingMyParentWants }?
  • Need a way to fire events. They don't really exist in React-land but they're handy!
  • What would this mean for SSR?
  • There's certainly no need to slavishly follow the exact design of hooks — some folks are thinking about interop between different frameworks, but if it turns out not to make sense then there's no need to treat it as a constraint

This issue might alarm some of you; rest assured I'm not going to immediately rewrite Svelte just because Sunil goaded me on Twitter, and this is just the very beginning of this process of exploration. It may go nowhere. If we do end up using some of these ideas, we could probably leverage svelte-upgrade.

Key point to note: even if we do end up creating slightly more work for Svelte than it currently has to do (by making it less clear which values could have changed, etc) we'd still be in a better place than React, since a) we don't have the overhead of a virtual DOM, b) we have all the affordance of HTMLx, c) ...including <style>.

I think it's at the very least worth considering — keeping Svelte feeling modern, and in line with evolving developer tastes, is an important consideration alongside the mission of making it easy to write small, fast apps (or making it difficult to write large slow ones).

kaisermann, Draggha and schneiderfelipePaulMaly, kaisermann and maxmilton

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.