Note: After working with react, redux, react-redux, redux-saga, redux-thunk, with and without typescript, I am trying to create a new and better framework for frontend async logic, with the benefits of redux-saga (without redux-saga) and excellent typescript support. I have made a promising MVP, but i have yet to figure out the takeLatest
functionality from redux-saga. This is the background for the following question.
My question, is a subject of performance.
I have created a class called Actions
and an example of how it can be used.
class Actions {
constructor() {
const actionNames = ['alpha', 'bravo', 'charlie', 'delta', 'echo', 'foxtrot', 'golf', 'hotel', 'india', 'juliet', 'kilo', 'lima', 'mike', 'november', 'oscar', 'papa', 'quebec', 'romeo', 'sierra', 'tango', 'uniform', 'victor', 'whiskey', 'x-ray', 'yankee', 'zulu'];
this.handler = (action) => console.log(`${action} was just executed.`)
Object.assign(this, {
cancel: () => {
this.handler = (cur) => console.log('Sorry, all actions are «cancelled».')
},
actions: actionNames.reduce((acc, cur) => ({
...acc,
[cur]: () => this.handler(cur)
}), {})
})
console.log('The reduce function was just executed!')
}
}
const {actions: actionsA, cancel: cancelA} = new Actions() // output: The reduce function was just executed!
actionsA.alpha() // output: alpha was just executed.
actionsA.foxtrot() // output: foxtrot was just executed.
cancelA()
actionsA.alpha() // output: Sorry, all actions are «cancelled».
actionsA.foxtrot() // output: Sorry, all actions are «cancelled».
const {actions: actionsB, cancel: cancelB} = new Actions() // output: The reduce function was just executed!
actionsB.alpha() // output: alpha was just executed.
actionsB.foxtrot() // output: foxtrot was just executed.
cancelB()
actionsB.alpha() // output: Sorry, all actions are «cancelled».
actionsB.foxtrot() // output: Sorry, all actions are «cancelled».
You may run the added code snippet to verify the output.
Here comes the question!
Is it possible to - somehow - avoid running the reducer each time a new instance of Actions
is created? I understand that this would involve changing the implementation of Actions
, but i would very much like the instance to behave as specified in the code snippet and example above.
My thinking is that this might be possible, and would be a great optimiziation given that new Actions()
would be called alot of times given the nature of a frontend application.
What i would try is to create a wrapping function/closure/factory/generator or a wrapping class that generates the Actions
class. See the example below for an example of what I am currently trying.
class ActionsGenerator {
constructor() {
const actionNames = ['alpha', 'bravo', 'charlie', 'delta', 'echo', 'foxtrot', 'golf', 'hotel', 'india', 'juliet', 'kilo', 'lima', 'mike', 'november', 'oscar', 'papa', 'quebec', 'romeo', 'sierra', 'tango', 'uniform', 'victor', 'whiskey', 'x-ray', 'yankee', 'zulu'];
this.handler = (action) => {}
const actions = actionNames.reduce((acc, cur) => ({
...acc,
[cur]: () => this.handler(cur)
}), {})
console.log('The reduce function was just executed in generator!')
Object.assign(this, {
Actions: class Actions {
constructor() {
// somehow implement the already created actions here. Is that possible?
}
}
})
}
}
const { Actions } = new ActionsGenerator() // output: The reduce function was just executed in generator!
const {actions: actionsA, cancel: cancelA} = new Actions() // <-- No output this time!
...
I would expect the output of my desired program change also.
If someone happens to know for certain that this is impossible, i would really appreciate an explanation.
Is this possible?
Thanks:)
You could use a proxy as value for the actions
property. This way you don't have to construct the (potentially large) object. Instead the proxy layer will return the right function when a particular action is read.
Not essential, but I would not overwrite the handler, but use a cancelled
property instead, which the handler will use to decide what to do.
class Actions {
static #actionNames = new Set(['alpha', 'bravo', 'charlie', 'delta', 'echo', 'foxtrot', 'golf', 'hotel', 'india', 'juliet', 'kilo', 'lima', 'mike', 'november', 'oscar', 'papa', 'quebec', 'romeo', 'sierra', 'tango', 'uniform', 'victor', 'whiskey', 'x-ray', 'yankee', 'zulu']);
#cancelled = false;
actions = new Proxy(this, {
get(obj, action) {
if (Actions.#actionNames.has(action)) return () => obj.handler(action);
}
})
constructor() {
this.cancel = () => this.#cancelled = true;
}
handler(action) {
if (this.#cancelled) {
console.log('Sorry, all actions are «cancelled».');
} else {
console.log(`${action} was just executed.`);
}
}
}
const {actions: actionsA, cancel: cancelA} = new Actions();
actionsA.alpha(); // output: alpha was just executed.
actionsA.foxtrot(); // output: foxtrot was just executed.
cancelA();
actionsA.alpha(); // output: Sorry, all actions are «cancelled».
actionsA.foxtrot(); // output: Sorry, all actions are «cancelled».
const {actions: actionsB, cancel: cancelB} = new Actions();
actionsB.alpha(); // output: alpha was just executed.
actionsB.foxtrot(); // output: foxtrot was just executed.
cancelB();
actionsB.alpha(); // output: Sorry, all actions are «cancelled».
actionsB.foxtrot(); // output: Sorry, all actions are «cancelled».