I have the following code, that looks like the following:
var shared = {
create: function(){
//do stuff on create
}
}
enyo.kind(enyo.mixin({
name: "CustomInput",
//properties unique to input.
kind: enyo.Input
},shared));
enyo.kind(enyo.mixin({
name: "CustomTextArea",
//properties unique to input.
kind: enyo.TextArea
},shared));
enyo.kind(enyo.mixin({
name: "CustomSelect",
//properties unique to input.
kind: enyo.Select
},shared));
I'm being informed by my peers that this is an incorrect way of doing things, and could potentionally break something, or be too confusing because they've never seen mixins used in this way.
My question is, is there anything wrong with doing this, in this way?
If you are extending kinds with mixins, here is a newer way to do this:
enyo.createMixin({
name: 'MyMixin',
mymethod: function() {
// do stuff
}
});
enyo.Control.extend({
mixins: ['MyMixin']
});
This will mix it in before instantiation.
If you wish to add properties at a run time, use mixin() funciton.
If it works, it's not wrong! However, I'm not sure how deep enyo.mixin goes, so you may not be getting everything you expect sometimes.
Related
So far I understand I need to build my own baseQuery. I could write graphql queries and mutations like in example here https://rtk-query-docs.netlify.app/examples/react-with-graphql, will I get full type safety for queries and mutations if I add types to query.builder like this builder.query<Device, void> or I must use something like this https://www.graphql-code-generator.com/docs/plugins/typescript-graphql-request#simple-request-middleware. In latter case how should my baseQuery look if I use generated hook for graphql-request library.
Here is example of hook from 2:
import { GraphQLClient } from 'graphql-request';
import { getSdk } from './sdk'; // THIS FILE IS THE GENERATED FILE
async function main() {
const client = new GraphQLClient('https://countries.trevorblades.com/');
const sdk = getSdk(client);
const { continents } = await sdk.continents(); // This is fully typed, based on the query
console.log(`GraphQL data:`, continents);
}
I am thinking something like:
import {getSdk} from './sdk'
const client = new GraphQLClient('https://countries.trevorblades.com/');
const graphqlBaseQuery = (someGeneratedQueryOrMutation, client) => {
const something = someGeneratedQueryOrMutation(client);
const { continents } = await something.continents();
return { data: continents };
};
Code does not really make sence but I hope you see where I am going with this. Thanks :)
Edit: By now there is a Grahql Codegen plugin available at https://www.graphql-code-generator.com/docs/plugins/typescript-rtk-query
Actually I started writing a plugin for the code generator a few days ago.
You can see the generated result here:
https://github.com/phryneas/graphql-code-generator/blob/5f9a2eefd81538782b791e0cc5df633935164a89/dev-test/githunt/types.rtk-query.ts#L406-L427
This would require you to create an api with a baseQuery using a graphql library of your choice like this.
A configuration would look like this
./dev-test/githunt/types.rtk-query.ts:
schema: ./dev-test/githunt/schema.json
documents: ./dev-test/githunt/**/*.graphql
plugins:
- typescript
- typescript-operations
- typescript-rtk-query
config:
importBaseApiFrom: '../../packages/plugins/typescript/rtk-query/tests/baseApi'
exportHooks: true
And I think for bundle-splitting purposes it would also work with the near-operation-file preset.
All that is not upstream yet - I will try to get that ready this weekend but don't know how much time it would take to actually get it in.
You could check the repo out, do a local build and install it with something like yalc though.
For a more basic approach without code generation you could look at this example or for an a bit more advanced setup (but also without full code generation, more integrated with existing tooling) you could look at this PR
I've monkey-patched my router to store the current route components in a session variable:
var Router = Ember.Router.extend({
customSession: Ember.inject.service('session-custom'),
location: config.locationType,
didTransition: function() {
this._super(...arguments);
this.get('customSession').set('currentEntity', this.get('currentRouteName').split('.')[0]);
this.get('customSession').set('currentDetailView', this.get('currentRouteName').split('.')[1]);
}
});
I know that this is not the cleanest of solutions, but writing the session to the console proves that at least those parameters are set.
In my controller, I'd like to listen for changes in these parameters, but somehow this does not work:
import Ember from 'ember';
import ApplicationController from './application';
export default ApplicationController.extend({
customSession: Ember.inject.service('session-custom'),
currentRouteNameChanged: Ember.observer('customSession.currentEntity', function () {
console.log("route changed");
})
});
i.e. "route changed" is never printed to the console.
This seems quite an easy fix, but I haven't been able to find a solution on SO.
Thanks!
Perhaps consider using an initializer to inject your session-custom service into your application’s controllers. To get there, some suggestions…
First, in the Router, and elsewhere, use the conventional, camelized short-hand to inject your service, like this:
sessionCustom: Ember.inject.service(),
...and be sure to reference sessionCustom in your code, instead of customSession.
Next, create a session-custom initializer, and inject the service into your application’s controllers:
export function initialize(application) {
application.inject('controller', 'sessionCustom', 'service:session-custom');
}
export default {
name: 'session-custom',
initialize,
};
Observing route changes from the controller should now be successful:
export default Ember.Controller.extend({
currentRouteNameChanged: Ember.observer(
'sessionCustom.currentEntity', function() {
console.log("CONTROLLER: ", this.get('sessionCustom.currentEntity'));
}
),
});
These changes, of course, can also be observed from the service itself:
export default Ember.Service.extend({
currentEntity: '', // <-- it's helpful to explicitly declare
currentRouteNameChanged: Ember.observer(
'currentEntity', function() {
console.log("SERVICE: ", this.get('currentEntity'));
}
),
});
I’ve created an Ember Twiddle to demonstrate this solution.
Here is my problem:
Aurelia app:
a few custom elements (already sharing a view via #UseView) doing almost the same thing (specific func shoud be defined by every element itself), how to manage shared code (inkl #bindable)?
How to refactor this:
https://gist.run/?id=897298ab1dad92fadca77f64653cf32c
The "shared" code you refer to in your question is lifecycle-related stuff in your custom elements, which isn't really suited for sharing. You would need to do inheritance, and with custom elements that's setting yourself up for a lot of headaches.
Rather than sharing code, why not focus on the things which are variable and try to make them configurable? By looking at your gist, that seems by far the most straightforward solution here.
Say you have a custom element that calls a function when a property changes. This function needs to be different for some instances of the element. You could accomplish that with a bindable function, and use the .call behavior, like so:
some-element.js
import { bindable } from 'aurelia-framework';
export class SomeElement {
#bindable value;
#bindable processValue;
valueChanged(newValue, oldValue) {
if (this.processValue) {
this.processValue({ val: newValue });
}
}
}
consumer.html
<some-element value.bind="myValue" process-value.call="myFunc(val)"></some-element>
<some-element value.bind="anotherValue" process-value.call="anotherFunc(val)"></some-element>
consumer.js
myFunc(val) {
console.log("val: " + val);
}
anotherFunc(val) {
console.log("val: " + val);
}
I'm dealing with a big json with a lot of editable values (*big means > 1000), entirely rendered on the same page, so my state is simply { data: bigBigJson }.
The initial rendering is quite long but it's ok.
The problem is that when an input triggers an onChange (and a redux action), the value is updated in the state, and the whole rendering happens again.
I wonder how people deal with that? Is there simple solutions (even not necessarily best practices).
Notes:
The json document is provided by an external API, I can't change it
I could separate the state in several sub-states (it's a multiple levels json), but hoping for a simpler/faster solution (I know it would probably be a best practice though)
I'm using react and redux, not immutable.js but everything is immutable (obviously)
––
Update (about DSS answer)
• (Case 1) Let's say the state is:
{
data: {
key1: value1,
// ...
key1000: value1000
}
}
If keyN is updated, all the state would be re-rendered anyway right? The reducer would return something like:
{
data: {
...state.data,
keyN: newValueN
}
That's one thing but it's not really my case.
• (Case 2) The state is more like (over simplified):
{
data: {
dataSet1: {
key1: value1,
// ...
key10: value1000
},
// ...
dataSet100: {
key1: value1,
// ...
key10: value1000
}
}
}
If dataN.keyN is updated, I would return in the reducer
{
data: {
...state.data,
dataN: {
...state.data.dataN,
keyN: newValueN
}
}
}
I guess i'm doing something wrong as it doesn't look really nice.
Would it change anything like that:
// state
{
dataSet1: {
key1: value1,
// ...
key10: value1000
},
// ...
dataSet100: {
key1: value1,
// ...
key10: value1000
}
}
// reducer
{
...state,
dataN: {
...state.dataN,
keyN: newValueN
}
}
Finally, just to be more specific about my case, here is more what my reducer looks like (still a bit simplified):
import get from 'lodash/fp/get'
import set from 'lodash/fp/set'
// ...
// reducer:
// path = 'values[3].values[4].values[0]'
return {
data: set(path, {
...get(path, state.data),
value: newValue
}, state.data)
}
• In case you are wondering, i can't just use:
data: set(path + '.value', newValue, state.data)
as other properties needs to be updated as well.
The reason everything gets rerendered is because everything in your store changes. It may look the same. All properties may have the same values. But all object references have changed. That is to say that even if two objects have the same properties, they still have separate identities.
Since React-Redux uses object identity to figure out if an object has changed, you should always make sure to use the same object reference whenever an object has not changed. Since Redux state must be immutable, using the old object in the new state is a guaranteed not to cause problems. Immutable objects can be reused in the same way an integer or a string can be reused.
To solve your dilemma, you can, in your reducer, go over the JSON and the store state sub objects and compare them. If they are the same, make sure to use the store object. By reusing the same object React-Redux will make sure the components that represent those objects will not be rerendered. This means that if only one of those 1000 objects changes, only one component will update.
Also make sure to use the React key property correctly. Each of those 1000 items needs its own ID that stays the same from JSON to JSON.
Finally, consider making your state itself more amenable to such updates. You could transform the JSON when loading and updating the state. You could store the items keyed by ID for instance which would make the update process a lot faster.
Quoted from Marionette.Behavior documentation
Finally, the user must define a location for where their behaviors are stored.
A simple example of this would look like this:
Marionette.Behaviors.behaviorsLookup = function() {
return window.Behaviors;
}
But window.Behaviors is undefined. When I use window everything is good. Do I miss something?
It's undefined because you probably haven't defined it yet. You would create an object window.Behaviors = {} that would be attached to the window when the app starts. From there you could register behaviors off of that and reference window.Behaviors like so,
window.Behaviors.ExampleBehavior = Marionette.Behavior.extend({
defaults: {},
events: {},
//etc..
});
Then inside of your behaviorsLookup, returning window.Behaviors won't be undefined. Here's the documentation explaining it further