Strict mode
Strict mode will be enabled by default in the future.
What is this?
Strict mode checks whether updating store/state happened in Store#receivePayload
.
It means that almin shows a warning if you updated store/state outside of Store#receivePayload
.
In other word, Strict mode requires that your store should be updated only in Store#receivePayload
.
How to enable strict mode?
You can enable Strict mode by Context
's options like the following.
import { Context, Dispatcher } from "almin";
const storeGroup = createYourStoreGroup();
const context = new Context({
dispatcher: new Dispatcher(),
store: storeGroup,
options: {
strict: true
}
});
Recommenced: use strict mode.
Notes
Almin will enable strict mode by default in the future.
A new feature like Context#transaction
can use only in strict mode.
Strict mode ensures consistency in almin.
Example
OK: This example is correct in strict mode:
class AStore extends Store {
constructor() {
super();
this.state = {
a: "value"
};
}
// Good: Update this store inside of receivePayload
receivePayload(payload) {
if (payload.type === "UPDATE_A") {
this.setState(payload.body); // Update!
}
}
getState() {
return this.state;
}
}
const store = new AStore();
const storeGroup = new StoreGroup({
a: store
});
const context = new Context({
dispatcher: new Dispatcher(),
store: storeGroup,
options: {
strict: true
}
});
const updateAStoreUseCase = ({ dispatcher }) => {
return () => {
dispatcher.dispatch({
type: "UPDATE_A",
body: "new value"
});
};
};
// No Warning
context.useCase(updateAStoreUseCase).execute().then(() => {
// do something
});
NG pattern 1: This example is incorrect in strict mode:
Warning(Store): AStore can only update own state in AStore#receivePayload in strict mode. If you update the state outside of AStore#receivePayload, please check the AStore.
import { Context, Dispatcher, Store, StoreGroup, UseCase } from "almin";
class AStore extends Store {
constructor() {
super();
this.state = {
a: "value"
};
}
getState() {
return this.state;
}
}
const store = new AStore();
const storeGroup = new StoreGroup({
a: store
});
const context = new Context({
dispatcher: new Dispatcher(),
store: storeGroup,
options: {
strict: true // strict mode!
}
});
// This UseCase directly update aStore.
// In other word, aStore is updated store outside of `Store#receivePayload`.
const updateStoreUseCase = ({ dispatcher }) => {
return () => {
// Warning: update state outside of receivePayload
store.setState({
a: "new value"
});
};
};
// Warning: execute and show Warning!!
context.useCase(updateStoreUseCase).execute().then(() => {
// do something
});
NG pattern 2: This example is incorrect in strict mode:
This is similar with Pattern 1(Almost same).
This Repopository#onChange
is called at different timing with Store#receivePayload
.
import { Context, Dispatcher, Store, StoreGroup, UseCase } from "almin";
// observable repository
const REPOSITORY_CHANGE = "REPOSITORY_CHANGE";
export class Repository extends EventEmitter {
save(entity) {
this.emit(REPOSITORY_CHANGE, entity);
}
onChange(handler) {
this.on(REPOSITORY_CHANGE, handler);
}
}
// singleton
const repository = new Repository();
// Store implement use repository
class AStore extends Store {
constructor({ repository }) {
super();
this.state = {
a: "value"
};
repository.onChange((entity) => {
this.setState(entity);
})
}
getState() {
return this.state;
}
}
const storeGroup = new StoreGroup({
a: new AStore({ repository }) // DI
});
const context = new Context({
dispatcher: new Dispatcher(),
store: storeGroup,
options: {
strict: true // strict mode!
}
});
// This UseCase directly update aStore.
// In other word, aStore is updated store outside of `Store#receivePayload`.
const updateStoreUseCase = ({ dispatcher }) => {
return () => {
// Warning: update state outside of receivePayload
repository.save({
a: "new value"
});
};
};
// Warning: execute and show Warning!!
context.useCase(updateStoreUseCase).execute().then(() => {
// do something
});
Issue
If you found an unexpected warning, please create a new issue.