-
Notifications
You must be signed in to change notification settings - Fork 27
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
Proposal for improved mutator API #97
Comments
@smikula any update on pushing this PR? One thing I wanted to do with Satchel is combining mutators together, for example, if I need to do two actions, instead of creating another action that mutates the two actions together:
The above calls the render function twice, it would have been nice if I can combine these two together then the store would upload together. The only way to control that is to merge these two actions into another action, but that is extra code for no reason. Something like this could work:
So it will just call the render once. Something similar could be for I know virtual dom solves this by updating the ui incrementally, but it would be nice to control when the observer is being fired. |
This is something of a pet project for me, so I'm not sure when it might get merged. (Though I do have most of it implemented.) Regardless, you can still follow this pattern perfectly well with the existing API. In fact, as a rule you should not fire multiple actions sequentially within a component for exactly the reasons you mention. I'd do something like: componentDidMount() {
const publisherId = this.props.match.params.publisherId;
const accountId = this.props.match.params.accountId;
initializeForm(publisherId, accountId);
} Then the // In publisherMutators.ts
mutator(initializeForm, action => {
// Select publisher here
});
// In accountMutators.ts
mutator(initializeForm, action => {
// Select account here
}); |
Preface
Satchel exists because, while we liked the Flux pattern and Redux in particular, there were a few things we wanted that Redux couldn't give us.
@observer
decorator and is highly performant by default. Whatever the front-end of our dataflow looks like, we know we want the store itself to be observable.Beyond those things, we really like Redux, and much of Satchel is influenced by it. These goals for this new mutator API aim to bring us closer to Redux while keeping the benefits above:
API
createMutator
The first challenge with mutators is that—because they act on observable objects—there needs to be a parent object on whose properties to act. Because reducers return a state object they can literally replace the entire state. With a little support from Satchel, we can have the best of both worlds: if a mutator returns a value then that value replaces the previous state object; if it does not return a value then we keep the same state object (which presumably has had some of its properties modified).
Creating a mutator for a simple state would look like the following. The state is simply a string, and the entire value of the state gets replaced when the mutator runs.
Creating a mutator that mutates an object would look like the following. Note that nothing is returned, so the reference to the state object itself remains the same.
combineMutators
Mutators can be combined to build up the state of the store. (TypeScript can derive the shape of the combined mutators from the child mutators.)
Effectively this creates a parent node in our state tree, so that our subtree looks like:
The combined reducer shouldn't expose
handles
because all the handling is done in the child reducers—except for the special case where we want the subtree itself to be null. We need a few new APIs for that.Satchel will make sure mutators are applied top-down, so that if
actionZ
is dispatched we will first define the root object and then run the child mutators which may set some properties on it.createStore
We will have to extend
createStore
to create a store from a mutator. Functionally this store would be just like any current Satchel store, except that it could only be modified by one of its mutators.Testing
To test a mutator, you would call
applyAction
on it and pass in some fake state. (This is the same API that Satchel will use internally to dispatch actions into the mutator.)Faking state is easy—just create a plain object in the shape that the mutator handles. Because the mutator is targetted to a very small portion of the state tree, the mock data should be trivial.
We also need a way to fake an action. This is harder since (by design) only Satchel can construct actions. We'll need to provide some sort of test utils APIs to do this.
Code organization
Now that mutators are tightly coupled to the state of the store, it makes sense to locate them with the store, preferably following the shape of the store. (Because mutators carry the schema there is no need to define the schema separately.)
The text was updated successfully, but these errors were encountered: