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
Related
I'm currently working on a project which has all of its styles declared in JSS. One of the "benefits" highlighted on many articles and the library docs is that it encapsulates styles. However I really am having a hard time customizing them, specially when it comes to styling that depends on the component's surrounding context (by context I mean parent elements, siblings, etc.).
Consider the following styles exported along a component called FieldDescriptor via the withStyles HOC:
info: {
fontFamily: theme.typography.fontFamily.light,
fontSize: "12px",
padding: "0 24px 8px 24px",
letterSpacing: 0.3,
},
This class will be found as FieldDescriptor-info-xxx on the element having that class. Now suppose that this component is child to another one that attempts to target the error class. You could target that class with something like [class*=FieldDescriptor-error] (personally I already consider this a very unclean approach) and it will work only on a development environment.
On production, classes will become unique (e.g. jss-xxx) and selectors like the one above will no longer be useful. My question is, what is the cleanest or "correct" approach to customizing component styles like this in JSS? I am either missing something really obvious or perhaps facing the limitations of JSS.
I am looking forward to solutions that do not require more tooling or code bloating, that would really miss the purpose of adopting JSS in the first place.
You can find an example using both withStyles and useStyles here
Try to think of a component as of a black box that intentionally hides implementation details from the outside world.
With this model, only component itself is responsible for it's presentation, so you need to ask that component to change something. In React world you do that most of the time by passing props to that component.
Inside of that component you can go multiple ways, combining the predefined classes depending on the props (preferred because static) or using function rules/values which let you access the props and define the styles per component instance.
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.
I am using react material ui combined with storybook and storyshots. I am trying to understand how I can test responsive elements in material-ui with jest or storyshots via storybook
I have Hidden elements in my components like the following
<Hidden xsDown>
{displayText}
</Hidden>
and stories that look roughly like
storiesOf("Card", module)
.addDecorator(muiTheme(myTheme))
.add("options bar", () => (
<Card {...someProps}/>
));
I have tried modding the breakpoints in my theme, which has an effect when viewing through storybook. However no matter what I have tried, the Hidden element never renders in my snapshots.
I have also tried not using the Hidden element and tried className styles to set display: none if theme.breakpoints.down('xs') is true. This produces the element in my snapshot like
<h6
className="MuiTypography-root CardOptions-label-1170 MuiTypography-
subtitle2"
>
View Route
</h6>
but nothing in this block tells me that the element is being hidden on xs screens.
It seem like I should be able to somehow toggle xsDown in the Hidden element to be true or false in storybook to have storyshot render or not render the element in my snapshot, but I am having no luck figuring that out.
I guess in general I am just wondering how most people are testing responsive UIs with jest. It seems like I should be able to accomplish this with snapshots but maybe I am missing something.
Thanks for your help
At the moment Storybook does not provide a responsive UI testing library out of the box.
However, you can use an additional library such as Chroma (company behind Storybook) or React screenshot test.
Which one you choose really depends on other factors.
Read more on Chroma: https://blog.hichroma.com/responsive-ui-component-testing-6d38b7e89dd4
I am working with the react-gsap library, and want to encapsulate specific <Tween> instances that do not need any props, because they are occuring multiple times in the same way.
Lets take a simple example of an instance, that doesn't need any props or state at all. Let's say this line
<Tween
to={{opacity: 0}}
duration={5}
/>
occurs really often in our code base, and we want to abstract it.
My first idea was to just create an SFC for that:
const HideTween = () => (
<Tween to={{ opacity: 0 }} duration={5} />
);
// and then ...
<HideTween />
but that seems not to work at all. The Tweens are simply not showing any effect.
I then came up with another idea (which i personally dislike) to just call the SFC. Instead of <HideTween /> , we now have
{HideTween()}
and voila, it works...
I am specifically curious now, why my first idea did not work at all. The question is not aimed into the gsap library directly, but more of a general form: Where, when and how can such an approach (of abstracting parts of your render into own functions) fail? If it is the library, how does it even achieve such a behaviour?
And why does it seem to work, when i call the function directly (i know this is kind of a bad approach)? Without any state or props present,
shouldn't <HideTween /> have the same effect on every render as {HideTween()}?
EDIT
Here is a minimal example
Exchange <Tweens /> in line 38 with the content of the Tweens SFC, and you will see the animation again.
You can share the same elements between different render methods by creating them ahead of the render cycle as you tried to do:
const HideTween = <Tween to={{ opacity: 0 }} duration={5} />
and then directly using the element (not instance) in the render methods:
<Timeline>
{HideTween}
</Timeline>
<Component /> is JSX sugar for creating an element of a react component. So your first idea didn't work as it would return an element returning an element of a Tween and not directly the Tween element. For usual DOM rendering this will work as expected, though. The second example works as you get the Tween element this way, but you're right to dislike it as it simply adds an unnecessary indirection.
Doing it this way you might think that react will reuse the same instance of the component in different places, but it will actually instantiate the component anew for each usage. Here is an example:
https://stackblitz.com/edit/react-rzq5q5?file=index.js
I assume this is intentional as sharing the same instance of a component seems to be quite a rare use case and with stateful components the state would be shared as well synchronising components in different parts of the app (which could end up being quite confusing).
Also check out this article on the difference between components, elements and instances (instances will be created by react for you): React Components, Elements, and Instances
Here I've set up a simple example trying out a few things: Example
In your Tween component:
class Tween extends React.Component {
static defaultProps = {
to: {opacity: 0},
duration: 5
}
...
}
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.