Svelte: Svelte Store Data update patterns

Created on 15 Oct 2018  路  7Comments  路  Source: sveltejs/svelte

Here would like to ask:

  • A solution to an issue.
  • Clarification on Data setting Patterns

Have used RactiveJS before and trying out Svelte. Svelte looks amazing so far. Currently I am struck with an issue where I have to update part of an Object.

For example, I have a Store defined like this:

const store = new Store({
  a: {
    b: {
      c: {
        name: "Test One",
        d: {
          e: {
            f: {
              g: {
                h: {
                  name: "Foo Bar"
                }
              }
            }
          }
        }
      }
    }
  }
});

The object a is being passed to a component with binding. Inside component, I would like to change "Test One" to "Test Changed".

I am doing like this:

this.set({
  a: {
    b: {
      c: {
        name: "Test Changed"
      }
    }
  }
});

In the component, I also have {a.b.c.d.e.f.g.h.name}. Now I get the error

Uncaught TypeError: Cannot read property 'e' of undefined.

For me its due to, when setting the name property of c, it is removing d.

Am I doing something wrong? Also, I found setting the data to the Store using Object pattern like above is not easy to use.

I have been following Ractive JS. RactiveJS had something like this.set("a.b.c.name", "Test Changed"). That was very handy to use.

Another one is with Array. RactiveJS had array methods inbuilt to take care of updates to an Array data. Now I need to set the data like below to append a single item to an Array:

store.set({
   arrayItem: store.get().arrayItem.concat({x: 10});
});

Assuming Svelte has inbuild smartness to identify the data changed and update only relavent parts. But how can I change x value of last array item that appended above and get the UI updated.

Can you please clarify this and also help me fix the problem.

Note: Initially I thought of posting it in Stackoverflow but as it also includes some clarifications for learning, posting here.

Most helpful comment

Svelte's philosophy is that the core API should only include things that can't be implemented in userland, unless the drawbacks in a particular case are overwhelming. That's how it's possible to have a 1kb Hello World, for example.

set and get are intentionally low-level. It's likely that we'll drift more in the direction of adopting patterns from packages like Immer...

// this is arguably much nicer than `store.set('a.b.c.name', 'Test Changed')`
store.set(({ a })=> {
  a.b.c.name = 'Test Changed';
});

...and baking state management opinions into Svelte (and Store) itself is most likely counter-productive; it risks promoting the wrong patterns while adding complexity.

All 7 comments

Svelte doesn't handle nested objects, but you can use setDeep in svelte-extras to handle that use case.

Unless you also use observeDeep any listeners to parent objects will execute, however.

@tivac Sounds great. I will use svelte-extras. Looks like it solves all the problems I listed above. I will give it a try. Thank you!

@tivac @Rich-Harris

I looked at the Svelte extras. They are really good. Although, setDeep for example, does not work if an object name mentioned in keypath does not exist in the Object. I have read Rich's explanation. I think its good how it is now.

However, the Store functionality looks very limited. To set some value to an array, getting the entire data using store.get() and then applying the change on it,

store.set({ arrayItem: store.get().arrayItem.contact("test"); }

at first, it was a surprise for me because it felt way too much for setting an array item. Then I did some tests to make sure it does not cause performance issues (Like rerendering the whole list). I was curious about how it performs if data is changed inside one of the array items. Even though Svelte is very performant in such cases, it is still not possible without some extra checks to identify what data is changed.

RactiveJS is amazing and one of the best libraries for JS community. Very simple to use and has a very small learning curve. One of the Serverside developers in our company was able to work on it alone and implement a small application. Having the first class data changing patterns made it easier to use. My favorite was get and set methods. Traditional and highly Predictable over other frameworks approach you just change the data as you do to normal Object, we check under the hood what data changed and apply the changes. I think similar patterns in Svelte gives a lot more confidence to use it.

Probably I am too much used to RactiveJS like patterns:). Just curious why svelte-extras are not part of Store class by the default.

Svelte's philosophy is that the core API should only include things that can't be implemented in userland, unless the drawbacks in a particular case are overwhelming. That's how it's possible to have a 1kb Hello World, for example.

set and get are intentionally low-level. It's likely that we'll drift more in the direction of adopting patterns from packages like Immer...

// this is arguably much nicer than `store.set('a.b.c.name', 'Test Changed')`
store.set(({ a })=> {
  a.b.c.name = 'Test Changed';
});

...and baking state management opinions into Svelte (and Store) itself is most likely counter-productive; it risks promoting the wrong patterns while adding complexity.

Thanks for the explanation @Rich-Harris .

Svelte's philosophy is that the core API should only include things that can't be implemented in userland, unless the drawbacks in a particular case are overwhelming. That's how it's possible to have a 1kb Hello World, for example.

That's very thoughtful 馃憤

set and get are intentionally low-level. It's likely that we'll drift more in the direction of adopting patterns from packages like Immer...

Actually, I was looking for this. Immer's patterns are really good. Looking forward to the adoption of it's patterns into Svelte.

...and baking state management opinions into Svelte (and Store) itself is most likely counter-productive; it risks promoting the wrong patterns while adding complexity.

Thanks for this. I completely understand now.

set and get are intentionally low-level. It's likely that we'll drift more in the direction of adopting patterns from packages like Immer...

That's would be very helpful!

Along similar lines, it would be nice to have automatic lensing support for the store. For example, when a parent component wants a child component to be associated with a specific sub-tree of the store, it could pass a lens for that subtree to the child. Then, the child component wouldn't even need to know the exact path to the store's node it is associated with. It would use the lens to update the node and correct subtree of the store would be updated by the lens.

@svapreddy @Rich-Harris Perhaps you can reopen this issue. Or if there's another issue to track this, please let me know.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bestguy picture bestguy  路  3Comments

clitetailor picture clitetailor  路  3Comments

Rich-Harris picture Rich-Harris  路  3Comments

1u0n picture 1u0n  路  3Comments

rob-balfre picture rob-balfre  路  3Comments