Vue js and fabric js logic - javascript

I am using Vue.js and one of my components is 2D canvas editor (by using fabric.js library).
The thing is, that the code for this editor and for the operations that I am making in it is getting pretty verbose to be part of the component script tag.
I tried using mixins and divided the code into separate mixins like canvasMoving, copyPaste, grouping.
Now while this works, I feel like this is still not the way to go, that maybe I should use specialized classes. Also I belive mixin is when you have a functionality to share between multiple components.
Because for example the copyPaste mixin, sometimes needs methods, that are contained in the mixin grouping. This then feels really wrong to me, that since the component includes both of those mixins, it works ok, but if I would remove one of them, it would stop working.
More over all of these mixins works with the canvas, but the canvas is initialized only in one of them and again, they can access it, because the component includes all the mixins, but if I remove the mixin that initializes the canvas, they all stop working because this.canvas will be undefined.
What is the correct approach here? I was thinking about classes with dependency injection, like having master class lets say Editor and it would have its dependencies (grouping, copyPaste, drawing) or something like that.
Then the only thing I do not know is how to connect my separate classes with the Vue.js component. Put the master class in the data object of my component?

So in the end I solved this by using normal classes instead of mixins. I also used bottlejs for dependency injection.
Now each class in its constructor specifies other classes, that it needs to use, so it is immediately clear which classes it is dependent on.
Also before when one mixin needed to call other mixin's method, it was a simple this.methodName() call with no knowledge about where this method is located, whereas now it is clearly stated by this._otherClass.methodName()
Since I needed access to canvas, store and also to emit events, I created class Editor, that has a method init(canvas, store, eventBus), because I can only create the Fabric canvas, after the HTML canvas is displayed. Bottle creates this class with empty fields and I call the init function with the parameters in mounted stage of my component.
All of my classes are then ancestors of EditorProvider class, which only has one getter for this Editor class (that it gets in a constructor and stores in a field), from where I can get any of the specified fields. So the call to store in any of my classes looks like:
this.editor.store.commit('anything')
Call to canvas:
this.editor.canvas.renderAll()
Call to eventbus:
this.editor.eventBus.emit('eventName')
My component now just imports the bottlejs and has access to all the classes by their names. The interaction is mainly by the canvas and window events, so I event created an EventHandler class, that moves all these event listeners from the component to separate class. So in the end in the component I only have HTML template and a few lines of imports and the script tag, which is now much more readable and the dependencies are clearly visible.

Related

How do popular React component libraries like MUI/Bootstrap change classNames on elements?

https://jquense.github.io/react-widgets/docs/Multiselect/
If you look at the multiselect at this link, and inspect element, when you click into the input you'll see the main div element change classnames from 'rw-popup-container' to 'rw-popup-container rw-slide-transition-exited'. The class 'rw-slide-transition-exited' contains display=none in css which makes the dropdown disappear.
This process of adding/subtracting classnames is extremely snappy and common among various React libraries like MUI/React Bootstrap. You can inspect the source HTML and see they are all doing it. How, exactly, are they doing this? I've looked through the source JS but I can't figure it out. It doesn't appear to be jQuery addClass()/removeClass() and they are doing conditional rendering in React (which is laggy from personal experience).
As you said, this is pretty commong in React libraries (VueJs and Angular libraries as well).
All the modern javascript frameworks have a way to conditionally set the styles of a component, and they just refresh that attribute, there's no need to re-render everything.
Particullary for React, you can unse the "className" proeprty for that, instead of passing an string you can pass a function, and that will dynamically change the classes in the component.
Example:
Using the same example you used, if you go here, you'll see the code for that component.
https://github.com/jquense/react-widgets/blob/f604f9d41652adc29ccd3455bf17997bc001d9ef/packages/react-widgets/src/Multiselect.tsx#L632
(I marked line 632, because that's were the magic happens)
className={cn(className, 'rw-multiselect')}
In there you can see that className is getting a function (since it's between curly brackets it will be evaluated instead of just passing the value).
And if I'm correct, it is using this other library: https://github.com/JedWatson/classnames
which allows you to conditionally set classes.

Is there a way to compile react components to html before build time?

I have a function that takes dom elements and operate on them. It is called pageTransition, and it takes two div elements, and performs a transition animation from the one to the other.
function pageTransition(div1, div2){//do the transition}
for example i can call this function like,
pageTransition (document.body.querySelector("#div1"), document.body.querySelector("#div2"))
That is simple, but let us say I want to pass React class components as my div elements. And that isn't possible because react components are class's not html elements. One quick reminder, this react components in the end will be compiled to div elements with some content during build time. I know I could get around this by doing this
...//the react class
render(
return (
<div id="div1">...</div>//this will allow me to call the above function with the same parameters
)
).
But I was just wondering if there was a magic way to compile this react classes before build time, so rather than giving the id's to the returned div's I was wondering if I could do something like this pageTransition(compile(reactClass), compile(reactClass));
The solution will depend on your intended purpose for pageTransition.
However, there are three potential options you may want to look into:
Statically render a React component into html markup or a string: https://reactjs.org/docs/react-dom-server.html#rendertostaticmarkup
Render two div elements in html and use a React portal to manage what is being rendered in the those divs. This could potentially replace what you are doing in pageTransition. https://reactjs.org/docs/portals.html
Use a ref to access the DOM element that is built from the React component: https://reactjs.org/docs/refs-and-the-dom.html
If you explain what pageTransition does it might help me find a solution for you.

Where inside a React/React Native component do I put a function? I see three options

I've included the image below so you can understand what I'm talking about.
For a React component I am able to create a class and have functions that display the content that is returned from those functions. I see three sections of a component that I can place a functions(see red boxes in image). I'm confused as to if it matters where an actual function is placed. All three of these functions do the same thing and yet are in different places.
Can someone please tell me if it matters or if it just preference of the developer.
Thank you.
C
Image below.
Outside of Component:
There is proper for functions that don't need to this keyword of component and only get arguments and execute some code and return something (if you want). If you don't need to access to this, it is the most convenient place to write functions.
Inside Component:
There is proper for functions that need to this keyword. for example if you need to access component states (this.state, this.setState(),...) and props (this.props,...), Here is the proper place.
Inside render() method of Component:
According to this ,Functions in the render method will be created each render which is a slight performance hit. It's also messy if you put them in the render, which is a much bigger reason, you shouldn't have to scroll through code in render to see the html output. It is proper to put them on the class instead.

ReactJS and targetting/wrapping elements like jQuery

I am trying to add 'sticky note' annotations (which i call TourPoints) to a React-based prototype I am creating. I created a TourPoint component which I have been manually 'wrapping' around elements of my interface as I go. The TourPoint displays the 'content' as a pink tag on the side of the element.
<TourPoint content="Sticky note content goes in this prop">
<button id="elementToWrap">Button element to annotate</button>
</TourPoint>
However, this gets a little messy and bloats my code... With jQuery, I used to be able to write a script where I could keep something like TourPoints neatly in a separate javascript file, then simply target DOM ids or classes to append elements.
$("#elementToWrap").wrap( "<div class='tourpoint'>Sticky note content goes here</div>" );
// $.append() or $.insertBefore() were also useful functions for this kind of thing
I am wondering how I might do a similar thing in React, and thought refs { useRef } might come to the rescue - but have not used refs before and can't quite get my head around if this is the right approach, or whether I am barking up the wrong tree with this.
The idea would be able to reference a ref globally (?) so that i can simply append the TourPoint to the element from a separate js/jsx file (sorry, no code example, as I really don't know what this would look like...)
The ease of having my TourPoints managed from a central file for the application what i am trying to achieve. The application has multiple pages and use React-Router.
Any pointers on how to think about this problem in the 'React' way would be most welcome.

Can you "hijack" rendering part of a Ractive template?

I have a "SuperSelect" control currently implemented as a Ractive component, which augments a regular drop-down select list with searching, filtering, extended option descriptions, and various other goodies. This generally works really well, except that I now need to fill one of these SuperSelects with approximately 7,800 options, and it gets really slow, and slows down the rest of the page as well. The problem seems to be Ractive's internal memory usage; if I re-implement the SuperSelect in vanilla JS, most of the problem goes away. Unfortunately, I can't see a good way to actually make use of my more-efficient SuperSelect without tearing out Ractive completely every place that it's used, which seems like throwing the baby out with the bathwater.
So, basically, I need a way to insert a chunk of DOM that's managed by other code into the middle of a Ractive template, while still allowing the controlling code to be notified when relevant keypaths are updated by the containing Ractive instance, and as far as I can tell none of the existing plugin/extension methods quite fit the bill. So far, I've come up with two hacks combining multiple plugin methods that might work:
Combine an adapter and a decorator. In this case, the decorator would simply replace whatever element it was attached to with the DOM fragment for the SuperSelect. A special SuperSelect control object would then be added to the Ractive instance's data with an adaptor that would let it participate in 2-way binding with the rest of the template, and independently communicate with the decorator code to update the SuperSelect DOM.
Combine a decorator with a mini-component and ractive.observe. In this case, the decorator would again replace a particular template element with the SuperSelect DOM fragment, but it would only be used locally within a component whose template consists of nothing but that one decorated element. The component would serve as a means of resetting the keypath root, so that the decorator code can observe a static set of keypaths in order to update the state of the SuperSelect DOM regardless of how the SuperSelect is embedded in a larger parent ractive instance.
Is there any simpler way to do what I need?
Yes – you could create a component with an empty DOM node and re-render its contents inside an observe handler:
const SuperSelect = Ractive.extend({
template: `
<div><!-- we'll render this bit ourselves --></div>`,
onrender () {
const div = this.find( 'div' );
this.observe( 'items', items => {
// render the items however we want
});
}
});
More complete demo here: http://jsfiddle.net/9w9rrr9s/

Categories

Resources