How can I use something like Fabric.js with React? - reactjs

Fabric.js is a framework that allows a canvas being used for various of things such as free hand drawing, SVG editing, adding text ext.
When I want to create an app that utilizes Fabric for the canvas functionality, I get stuck in the React principle of passing props down and lifting the state up.
Normally I'd want to create a component that provides the canvas with initializing Fabric on it like this:
componentDidMount() {
this.theCanvas = new fabric.Canvas('main-canvas', {
preserveObjectStacking: true
})
}
some local variable gets assigned a fabric.Canvas object, after it mounted a canvas with the id="main-canvas" into the app.
render() {
return (
<React.Fragment>
<div id="canvas-container">
<canvas style={{border: 'solid 1px #555'}} id='main-canvas' />
</div>
</React.Fragment>
);
Additionally I'd construct some kind of UI elements like a toolbar, tool-settings, export buttons, undo/redo ect.
Exemplary a draw-button that toggles drawMode for the canvas.
render() {
return(
<Button
onClick={this.props.toggleDraw}
style={{
backgroundColor: this.props.drawMode ? 'red' : 'blue'
}}
>
Freehand
</Button>
);
}
The problem is now, that Fabric needs to be told about this drawMode set to true or disabled when set to false:
this.the_canvas.isDrawingMode = this.props.drawMode;
The the_canvas.isDrawingMode sets the currently Fabric canvas object, that exists in the Fabric component into drawing.
Now I want to know how I organize this in the best way.
I could get rid of the Fabric component and initialize it in the Root component, here App.js. A toolbar component could pass the state all the way up into App.js and toggle the setting there. I would prefer not to do this since it makes the whole app less modular.
Use a store like Redux, MobX or React.Context for this matter to provide a global state so every toolbar element can have direct access to theCanvas.
I could remove the fabric.Canvas initialization completely from the React UI and include it directly into the root HTML file the traditional way then constructing wrapper functions in the UI elements.
To generalize my question, since this problem is not limited to a thing like Fabric.Js but to any case where I want to use a library that provides external functionality into a React app, what's the best practice to use here?
There are react modules that provide fabric into my app but all I found, like "react-fabricjs" that have been suggested in similar questions here, are several years old and not maintained anymore so I don't want to use them at all.

Related

Reusable components structure (react native)

I want to seek advice regarding reusable components structure in react-native. I wanted to make them lean and adaptive. What I thought was to have generic components as wrappers and then have specific components using those wrappers. e.g. For products carousel I pass products data to Carousel component (just a FlatList) that renders Card component multiple times that has products details and product related icons. But what If I want to have categories or anything else inside card?
What I thought is to make card content passed as props
<Carousel>
{.... // ProductContent}
</Carousel>
<Carousel>
{.... // CategoriesContent}
</Carousel>
But it seems like I am over complicating things as I'll pass data to carousel, then carousel will pass it to card then card will pass it back to my content and carousel is mere a Flatlist and card is mere a TouchableOpacity. And also it will not look clean as I will have to define the content wherever I am using the Carousel. Why not just create two separate carousel components
<ProductCarousel />
<CategoriesCarousel />
Similarly I have a <PopUpModal /> component. which I am using for showing product details. Should I pass product content as children to keep content generic or just create <ProductDetailModal /> as a component and create more modals if required
So the point is whether to have specific bits and pieces of the app as components so that connecting them will complete the puzzle or to have generic customizable wrappers like components. Or something in between
I recommend atomic design.
Its hard to explain it here, so Ill leave a link.
https://bradfrost.com/blog/post/atomic-web-design/
The key point is to break(modularize) everything into tiny, replacable & reusable bits, and actually reusing and replacing them.
Another important, yet often neglected point is that separating smart and dumb components.
https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
This is surely neglected and also seems cumbersome to aplly, but will simplify the codebase by detaching view related logic to data(api) related logic.
So those are the two rules I try to stick to.
P.S. Just as im_baby has pointed out in the comments, there is no answer, and we all compromise at some point. So try to be long sighted and practical, dont be dogmastic to rules, neither be short sighted and mess up the overall code quality and structure for immediate comfort
You will make a component like this giving the parent component all the liberty to change it through props.
render() {
const { all the props that you want to give your component} = this.props;
return (
<Carousel>
{this.props.childern} // like this you can design your one carosal and cahnge the data/view in the carosal.
</Carousel>
);
}
Then in your parent component you need to import this component like this:
import CarouselComponent from '../CarouselComponent'; //path to your component
<Carousel>
<View>
//any view you want to be rendered in the modal
</View>
</Carousel>

declarative composition vs imperative in react js

While designing the application in react js to increase the reusability I have used the Tabs and then passed the tabs and headers something like this
const tabs ={
"tabHeader1": TabContent1,
"tabHeader2": TabContent2
}
<SwipableTabs tabs={tabs} />
Now my confusion arose when I had to render them permission based , In order to avoid if else juggling I have designed a component like below :
<ProtectedAction>
{children}
</ProtectedAction>
my ProtectedAction component will check for permission and will render the children based on that. Which is exactly what react suggest(be declarative).
Now when I see the above example like tabs which is data driven I am forced to use if else again which I wanted to get rid of.
Please suggest if any better approach is possible .

What does "animated" do in react-spring?

I am currently getting to grips with the react-spring animation library.
In some of the CodeSandbox demos (e.g. https://codesandbox.io/embed/j150ykxrv) in the documentation, something is imported called "animated":
import { Transition, animated } from 'react-spring'
and then used like so:
{this.state.items.map(item => styles => <animated.li style={{ ...defaultStyles, ...styles }}>{item}</animated.li>)}
In other examples this isn't used:
import { Spring } from 'react-spring'
<Spring
from={{ opacity: 0 }}
to={{ opacity: 1 }}>
{props => <div style={props}>✌️</div>}
</Spring>
I can't find any mention in the documentation of what this does or why it is used, as it seems you can animate by just passing animated style props into a component.
Are the uses in the documentation part of a legacy version?
Native is optional, if you set it (and then you need the component to extend from animated.xxx) it won't render out the animation like normally react animation libs would do, in other words they call forceUpdate or setState on every frame, which is expensive. With native it will render the component once, then animate in the background using a requestAnimationFrame-loop which sets the styles directly. The values you pass to your target div (or whatever) are not numeric values but classes that receive update events, this is why you need to extend.
Rendering through react is not obsolete, though, it is the only way you can animate React component props. If you have a foreign control, or a D3 graph for instance, you would simply blow props into it while the spring renders them out.
Looking further into the docs, I can see it is used for "native" rendering.
This allows react-spring to bypass React for frame updates. The benefits of this method are improved performance.
It is recommended to use this approach
"Try doing this in all situations where you can"
Just be aware of the following conditions:
native only animates styles, attributes and children (as textContent)
The values you receive are opaque objects, not regular values
Receiving elements must be animated.[elementName], for instance div becomes animated.div
If you use styled-components or custom componemts do: animated(component)
If you need to interpolate styles use interpolate
Summarised benefits:
Your application will be faster, the difference really can be night
and day
You get quite powerful interpolation and keyframing tools (see
below)
You get to animate scrollTop and scrollLeft out of the box (which
React can't normally handle)
Looks like it is used for doing native rendering,take a look a the Transition component , it has a native prop

react animation with gsap without react-transition-group and ref

I have a question with GSAP and react, as I read from some tutorials, they all use react-transition-group and also many of them use ref as an alternative selector for GSAP how ever, if I use ref in my case, the whole page will be animated, I just want a single element to animate so I use id selector, and it works totally fine like this
import React from 'react';
import { TweenMax } from 'gsap';
import uuid from 'uuid';
import '../styles/homePage.css';
class HomePage extends React.Component{
startAnimation=(pic)=>{
TweenMax.from(`#${pic.id}`, 1, {
opacity: 0,
x: -100,
y: -100
});
}
render(){
const PicsNum = 15;
let pics = [];
let pic = {};
for (let i = 5; i <= PicsNum; i++) {
const picPath = `/pictures/testingPics/${i}.jpg`
pic={id:`a${uuid()}`, picPath}
pics.push(pic)
}
const renderPics = pics.map((p, i) => (
<div
key={i}
className='img-container'
>
<img src={p.picPath} className='pic' id={p.id}/>
<button onClick={()=>{this.startAnimation(p)}}>click</button>
</div>
))
return (
<div className='pics'>
{renderPics}
</div>
)
}
}
export default HomePage;
can someone please tell me why should I use react-transition-group and what can go wrong if I want to use animation without it like I am doing? thank you very much
So, what you are doing here is absolutely fine for simple animations. It's only when your logic and animations start becoming more complicated that you may find it has downsides.
The main problem you may encounter as the complexity of your logic / animation increases is that you actually are now using two different libraries to target the dom. React wants to be completely in control of the dom so it can do its thing. GSAP however also is now looking for an element in the dom and controlling it's state, and react doesn't know about so now things might get out of sync. React might re-render that component, resetting your opacity to 1, when the user has already triggered the fade out.
React-transition-group can be a useful tool in simplifying working with animating components in and out, but it is not the only way to do it or the be all and end all of react animation, so don't feel like you have to use it. Just maybe look into the ways in which is simplifies the code you have to write for every component you want to animate in or out. (It gives you specific lifestyles for animating in and out, and a callback to remove the component post animation, which is the bulk of the boilerplate for component transitions).
In the case of the first issue I mentioned Transition-group is useful here because all your animation code is wrapped within the helpers it provides, so react knows: 1)Your animating... don't do anything till you've finished... 2)now you've finished and I'm back in control.
But there are other options outside of transition group to deal with this dichotomy of dom control:
You can try to be super smart and declarative about it... use refs to access the elements and pass them to gsap animations that are triggered and controlled by state/props.
But there are brilliant libraries that will take all the hassle out of worrying about state and animation and things like https://github.com/azazdeaz/react-gsap-enhancer
This is a wonderful higher order component that just makes sure any changes that gsap makes to the elements are noticed and preserved across react re-rendering and state changes.
Honestly it's a bit magic, and makes working with react and GSAP an absolute pleasure.
Also to answer your question about 'Why refs' instead of the useful 'just pass a string of the ID to the gsap function':
There isn't a right in wrong here. A ref in react will store a pointer to that Dom element in memory. Making it a convenient lookup. Its main advantage is the reference to that element will not expire upon a react re-render. If you manually select an element using GetElementById, and that Dom node is replaced by a react re-render, then your variable reference will become undefined and you'll have to call GetElementById again. GetElementById is very cheap in performance terms, it's not about performance, just avoiding the boilerplate of having to 'find' a new reference to the Dom element after every re-render.

How can I trigger a click on an element inside a child component (that I don't have access to)?

I have installed react-file-base64 into my React JS project and have implemented it like so:
import FileBase64 from 'react-file-base64';
import FileUpload from '../../forms/FileUpload'
...
class MyComponent extends Component {
render() {
return (
<FileUpload buttonText='Upload New Image'>
<FileBase64
multiple={ false }
onDone={ this.changeProfileImage }
/>
</FileUpload>
)
}
}
The code is obviously condensed for brevity.
As you can see, I've wrapped the FileBase64 component inside a custom FileUpload component - to do the old JS/CSS trick of hiding the file upload and triggering it via a different button press.
Given that I do not have direct access to edit the FileBase64 component, since it's been installed by NPM (and will possibly be updated by it in the future), and given that it is not a direct input element but rather a custom component that renders one - how can I trigger a click on the input element rendered by the FileBase64 component, from inside my FileUpload component?
You have a few options.
Reconsider using react-file-base64
This is a pretty minor NPM module, so ask yourself: is it worth using a few dozen lines of someone else's code instead of writing the functionality myself? Open source is amazing and leveraging other people's work can be a lifesaver, but learn to recognize when to lean on it and when not to.
Fork react-file-base64
Fork the original project and add whatever functionality you need to meet your requirements. Ideally do it in a well-written, well-documented way so that you can later open a pull request and contribute back to the project in a meaningful way.
Hack it a bit
It's good to stay inside of React as much as possible, but there are ways around it. You can, for example, still select DOM elements using plain old JavaScript. Remember that stuff? ;P
This would probably work fine - wrap the <FileBase64 /> component in a <div> that you can use to select any nested child <input> elements.
class MyComponent extends Component {
...
onBtnClick() {
this.inputWrapper.getElementsByTagName("input")[0].click();
}
render() {
return (
<FileUpload buttonText='Upload New Image' callback={this.onBtnClick} >
<div ref={(el) => this.inputWrapper = el} >
<FileBase64
multiple={ false }
onDone={ this.changeProfileImage }
/>
</div>
</FileUpload>
)
}
}
I dunno how exactly you're handling <FileUpload /> click callbacks but you get the idea. After a component renders, its DOM elements are laid bare for you to access. The trick is figuring out how to select those elements in the first place, and being careful that you don't break React in the process. But selecting an element and triggering a "click" event is pretty benign.
There are several triggers for this component that maybe suits your needs. Some of them are:
beforeUpload: Triggered before uploading. return true to continue or false to stop uploading.
doUpload: Triggered after the request is sent(xhr send | form submit).
onabort:riggered after you aborting a xhr.
uploadSuccess: Callback when upload succeed (according to the AJAX simply).
If you see the plugin documentation you can be how they work in detail, as well as more different events to interact with your input element inside your FileUpload component.

Resources