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

Computed props with rest arguments get... weird #1544

Closed
Rich-Harris opened this issue Jun 13, 2018 · 6 comments
Closed

Computed props with rest arguments get... weird #1544

Rich-Harris opened this issue Jun 13, 2018 · 6 comments

Comments

@Rich-Harris
Copy link
Member

Discovered during #1540, opening a separate issue because I'm not entirely sure what to do with it.

If you have a situation like this (won't work in the REPL, because object rest support is waiting on #1542)...

<pre>{JSON.stringify(props)}</pre>

<script>
  export default {
    data: () => ({
      unwanted: 1,
      wanted: 2
    }),

    helpers: {
      JSON
    },

    computed: {
      props: ({ unwanted, ...props }) => props
    }
  };
</script>

...then it will initially render this:

<pre>{"wanted":2}</pre>

But if wanted changes to 3, you get this:

<pre>{"wanted":3,"props":{"wanted":2}}</pre>

And then this:

<pre>{"wanted":4,"props":{"wanted":3,"props":{"wanted":2}}}</pre>

Somehow, we need to exclude props from the object that props is based on. But we can't do that like this...

computed: {
  props: ({ unwanted, props, ...everythingElse }) => everythingElse
}

...because Svelte will see that as props depending on itself (at least, it will post-#1543), which is an error.

Banning object rest in computed property arguments isn't a solution, because people can just do this instead:

computed: {
  props: (state) => {
    const { unwanted, ...props } = state;
    return props;
  }
}

Maybe in cases where a computed property depends on the entire state object (either explicitly, or because its argument has a rest element) we remove the property itself? So in the case above,

state.props = props(removeProp(state, 'props'));

// later
function removeProp(obj, prop) {
  const clone = {};
  for (const k in obj) {
    if (k !== prop) clone[k] = obj[k];
  }
  return clone;
}

It feels like we're getting into some weird territory though, and it wouldn't solve this case, in which b.b.b.b.b will eventually equal b:

computed: {
  a: ({ unwanted, ...rest }) => rest,
  b: ({ a }) => a
}
@TehShrike
Copy link
Member

This doesn't solve any of the real issues, but my personal choice for the clone-without-this-property pattern is

const clone = Object.assign({}, obj)
delete clone[k]

even though it's still not great.


It's true there are weird territories you could get into, but personally something like your a -> b computed property example looks fishy enough that it wouldn't surprise me if there were weird effects, whereas having props show up in props: ({ unwanted, ...rest }) => rest threw us for a hard loop.

¯\_(ツ)_/¯

@Conduitry
Copy link
Member

This was also taken care of in #1628 I think.

@fjorgemota
Copy link
Contributor

This same issue happens if you pass the entire state object without using object rest. See in REPL. (try changing wanted value..)

Is this an expected behavior? (or should I create an new issue just for that?)

@fjorgemota
Copy link
Contributor

ping @Rich-Harris and @Conduitry (sorry for the ping, just wanna to confirm this and the issue seems related)

@Conduitry Conduitry reopened this Aug 13, 2018
@Conduitry
Copy link
Member

No big opinions on whether that belongs to this issue or it should be another one - but it does seem like that's a bug though. If we're going to automatically exclude the current computed property in object-rest situations, it's probably a good idea to do so in full-state situations. Perhaps here should always use exclude, regardless of whether hasRestParam is set.

Rich-Harris added a commit that referenced this issue Aug 15, 2018
exclude current prop in computed properties using entire state #1544
@Rich-Harris
Copy link
Member Author

Fixed in 2.11 — thanks

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