-
Notifications
You must be signed in to change notification settings - Fork 78
Stores reference #341
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
Stores reference #341
Conversation
| }); | ||
| ``` | ||
|
|
||
| `State` defines the shape of the global store using an interface. In general state should be serializable. This improves performance and makes it easier for Dojo to determine when changes to the data occur. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
State should be completely serializable, this is important for features such as history.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that it usually should be. How would you recommend handling state that contains TypedArrays for large data sets or BigInt?
agubler
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@devpaul A few comments, but this looks like a good start!
|
|
||
| > main.ts | ||
|
|
||
| ```ts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think that we should use the helper from StoreInjector, registerStoreInjector for the example:
import { registerStoreInjector } from '@dojo/framework/store/StoreInjector';
import Store from '@dojo/framework/stores/Store';
import { State } from './interfaces';
const store = new Store<State>();
const registry = registerStoreInjector(store);There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally. I forgot about that :)
|
|
||
| ### Operations | ||
|
|
||
| Stores cannot be modified directly. Instead four operations are available for modifying state: `add`, `remove`, `replace`, and `test`. These operations are represented by simple objects based on the [JSON patch](http://jsonpatch.com/) format, but in practice helper functions will always be used. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to mention JSON patch here, although being inspired by JSON patch is where we started it is an implementation detail that we could change in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. After writing this I spoke w/ @maier49 and found that we deviate from JSON patch in a lot of small ways
| A process simply defines an execution flow for a set of data. To execute a process it needs access to the store to create an executor. Then the executor can be provided a payload to act upon. | ||
|
|
||
| ```ts | ||
| import { login } from 'commands/login'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be processes? And also prefixed with ./?
|
|
||
| Note that the documentation in this section is intended to show how widgets and state are connected. For a more detailed look see the [Widgets]() reference guide. | ||
|
|
||
| ### Container |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we talk about the StoreProvider first please?
| const login = createProcess('login', [ fetchUser, loadUserData ], [ resetUserOnError ]); | ||
| ``` | ||
|
|
||
| #### Excuting a Process |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it's worth talking about this in the StoreProvider / Container sections as that's the main place that you will have access to the store? I'm not sure we should be suggesting people to export the store instance from main.ts.... Maybe we should have a section on creating initial store state, which would normally be done in the main.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You make a good point. I wanted to show the most basic usage of a process, but in doing so it could be reinforcing a bad pattern.
|
|
||
| `UserProvider` extends `WidgetBase` allowing us the opportunity to redefine the widget's properties. In this case `UserProvider` does not accept any properties. It gets all of the information it needs from the store. The `StoreProvider` occurs as part of `UserProvider`'s render and provides its own renderer just like any other widget. | ||
|
|
||
| The `StoreProvider` is more robust than a `Container`. Since it is always wrapped by a widget it gives the opportunity to decide what properties should be provided by the outside widget and which should be provided from the store. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is true, it's not always wrapped by a widget nor would I recommend doing that by default. I would also start with using the StoreProvider inline and then think about where to abstract when it becomes required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm maybe this part can be removed entirely. For me it was novel when the StoreProvider became available because Container didn't allow properties to be redefined it was actually a lot of work to connect a store to a widget and then change the properties. So while I was really excited about StoreProvider for this reason future Dojo users can just take this for granted 😅
|
|
||
| - `renderer`: A render function that has the store injected in order to access state and pass processes to child widgets. | ||
| - `stateKey`: The key of the state in the registry. | ||
| - `paths` (optional): A function to connect the Container to sections of the state. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"connect the provider to sections of the state"
|
|
||
| The `StoreProvider` has two main ways to trigger invalidation and cause a rerender. | ||
|
|
||
| 1. The recommended approach is to register `path`s on container creation to ensure invalidation will only occur when state you are interested in changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"register paths by passing the paths property to the provider...."
| export class TypedStoreProvider extends StoreProvider<State> {} | ||
| ``` | ||
|
|
||
| **However** in order for TypeScript to infer this correctly when using w(), the generic will need to be explicitly passed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using tsx infers the renderer functions arguments correctly, do you think we should demonstrate this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds great. Why does it work for tsx and not w()?
| }); | ||
| ``` | ||
|
|
||
| # JSON Patch and Store operations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As before I don't think we should mention JSON path in the reference guide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's some advanced functionality here that I want to cover
- that stores will automatically create the underlying structure
- that stores will rarely throw an error
- that adding and replacing past the end of an array will add to the end of an array
Maybe keep this section and remove the references to JSON Patch
|
Thanks for your feedback @agubler! Hope to have time to work on this soon |
This is a draft of the stores reference guide.
StoreProvider.Resolves #324
We added a discussion about Dojo's implementation of JSON patch in the supplemental section after writing #339 and discussing the
statefeature with @maier49. Dojo differs quite significantly from JSON patch in that it tries to do the right thing regarding uninitialized state and avoid throwing errors.