Skip to content

Conversation

@devpaul
Copy link
Member

@devpaul devpaul commented May 17, 2019

This is a draft of the stores reference guide.

  • Introduction is mostly complete. Some cleanup on the features will likely need to happen when I'm done writing and have full view of everything.
  • Basic usage is done. It contains everything a person needs to use state from store to widget written in a manner that progresses from operations thru StoreProvider.
  • Supplemental is done

Resolves #324

We added a discussion about Dojo's implementation of JSON patch in the supplemental section after writing #339 and discussing the state feature 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.

@devpaul devpaul requested a review from sbinge May 17, 2019 18:42
@devpaul devpaul marked this pull request as ready for review May 21, 2019 02:31
@vansimke vansimke added the reference guide documentation label May 21, 2019
});
```

`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.
Copy link
Member

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.

Copy link
Member Author

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?

Copy link
Member

@agubler agubler left a 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
Copy link
Member

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);

Copy link
Member Author

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.
Copy link
Member

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.

Copy link
Member Author

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';
Copy link
Member

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
Copy link
Member

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
Copy link
Member

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

Copy link
Member Author

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.
Copy link
Member

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.

Copy link
Member Author

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.
Copy link
Member

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.
Copy link
Member

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.
Copy link
Member

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?

Copy link
Member Author

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
Copy link
Member

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.

Copy link
Member Author

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

  1. that stores will automatically create the underlying structure
  2. that stores will rarely throw an error
  3. 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

@agubler
Copy link
Member

agubler commented May 30, 2019

@devpaul Sorry to be a pain but as #357 has been merged, could you update any references to framework/widget-core to framework/core. Thanks!

@devpaul
Copy link
Member Author

devpaul commented Jun 1, 2019

Thanks for your feedback @agubler! Hope to have time to work on this soon

@rorticus rorticus mentioned this pull request Jul 19, 2019
@sbinge sbinge closed this in #453 Jul 30, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

reference guide documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reference guide: Dojo Stores

3 participants