Tag: performance

React-Redux: Connecting all children (part 2)

React-Redux: Connecting all children (part 2)

A clearer look into the performance implications of different approaches to connect components to the redux store, backed by real data.

React-Redux: Connecting All Children

React-Redux: Connecting All Children

It appears to be a fairly common notion that having a single connected container component in your react-redux project is a recommended idea for a variety of reasons. The main one being that it was suggested by the main react and redux teams back in 

FLIP – Performant Layout Transitions even with Left/Top/etc., with React Hooks!

FLIP – Performant Layout Transitions even with Left/Top/etc., with React Hooks!

FLIP is a way to animate elements on the page performantly even when changing properties like left, top, height, width, etc.

Here’s the experiment for you to take a look at: https://jayant.dev/experiments/flip-animation-technique
Note: We’ll do this in React, feat. some TypeScript.

If you took a look at a previous post I wrote, you know that the properties I mentioned above aren’t performant to animate, and result in janky motion anyway. It also mentions that sometimes these properties are your only hope. So is there no way we can do 60fps for such use cases?
Sure there is!

Presenting FLIP.
It stands for First – Last – Invert – Play.
Here’s what it means…

First
Get the current client rect for the element, so you know where the element is/was at the start.

Perform the action that results in the layout change to occur.

Last
Get the client rect for the element after the intended action completed, so you know where it is/was at the end.

Invert
Make the element appear at the same place as it was at the beginning of this process. Effectively meaning that it’ll show up as it was during the First phase, and as far as the user cares nothing has happened yet and the element is still shown in the same place as it was during the First phase.

Calculate the offset between the First and the Last phases to know the X/Y position difference, and Scale difference.

Play
Now that your element is being shown at the First phase position, and you know the offset between that and the Last phase, you can effectively just animate on the translate and scale properties. You’d translate on the positional difference, and scale on the proportional size difference.


Alright. That was the explanation of what FLIP means, and you’re around 300 words through, and we still don’t know how to do this. Let’s do this, in React.

We’ll use the latest and greatest in React to do this. Hooks.

Since we have to read properties from the layout after a layout change has been triggered, the useLayoutEffect makes the most sense.
We also need to get a reference to the element itself to read things from, for which we’ll use the useRef hook.

If it makes it easier for you to have the entire source before you continue, here you go: https://github.com/jayantbh/experiments/blob/master/src/components/FlipAnimationTechnique/index.tsx

We’ll work on a simple animation that changes the position and size of an element between two different states.

const before: CSSProperties = {
  height: '100px',
  width: '100px',
  left: '200px',
};

const after: CSSProperties = {
  height: '200px',
  width: '200px',
  left: '-200px',
};

And, that we’ll be applying one of these styles at all times based on a boolean like:

const elementRef = useRef(null as null | HTMLDivElement);
const [animated, setAnimated] = useState(false);
const toggleAnimation = useCallback(() => setAnimated(!animated), [animated]);
useAnimation(elementRef, animated);
...

<div
  ref={elementRef}
  className={css['element-common-styles']}
  style={animated ? before : after}
/>

Bit of an explanation on this since some stuff is new.
The useState hook gives you a state variable, and a setter for it.
The useCallback hook basically memoizes a function you pass to it, so you’re not creating a new function on each render. We use it to create a state setter function.
The useAnimation hook is our custom hook containing the logic that we’ll discuss below. Our logic requires the element reference (elementRef), and a boolean for whether the animation is toggled on or not (animated).

Now to make our animation work, we’ll create a custom hook (useAnimation). It’s not necessary to do so but it’ll keep the component code a bit cleaner. Remember that all code inside this hook can easily be put directly inside the component too. Let’s discuss what useAnimation will do.


After the first render, before any animation has been triggered by us, we get the element reference using our useRef hook. Subsequently, the useAnimation hook is fired once, but it does nothing because we will track the previously recorded client rect in our logic to use as the “First” phase rect, as such, our logic would know that there’s no previously recorded rect on the first run, and does nothing.

It’s also important to ensure that the useLayoutEffect hook doesn’t run again when we’re setting client rect in state, so we’ll track the previous value of animated property. If it remains the same we don’t want any animation logic to run again.

export const useAnimation = (elementRef: MutableRefObject<null | HTMLDivElement>, animated: boolean) => {
  // Maintain state of the element client rect
  const [clientRect, setClientRect] = useState(null as null | ClientRect);
  // Track whether the hook is being called with the same animation state.
  const { animated: prevAnimated } = usePrevious({ animated });

  // Run a side-effect to work in sync with layout changes because we'll be reading layout stuff
  useLayoutEffect(() => {
    // If this was fired with the same animation state as the last call, do nothing
    if (animated === prevAnimated) return;
    if (!elementRef || !elementRef.current) return;

    const el = elementRef.current;
    // Get first client rect from persisted state
    const first = clientRect;
    // Get current client rect from DOM
    const last = el.getBoundingClientRect();

    // Persist current client rect to state, so this is read at the "first" client rect next time
    setClientRect(el.getBoundingClientRect());

    // If either a persisted, or current client rect is missing, do nothing
    if (!first || !last) return;
    // ... rest of the code

So, on the first run, if (!first || !last) return; is going to terminate execution because first would be null. And animated will be the default value from useState.

The next time when the value of animated would have changed, we’ll have the clientRect persisted from the last time, and this forms what will be the “First” phase rect, and right after that we read the current element rect to get the “Last” phase rect.

That covers First, and Last.

The next time this hook, and hence the useLayoutEffect hook inside it will be fired is when the value of animated will change, which will have followed a layout change, making it safe for us to read any updated element layout properties BEFORE anything has been painted.

(You can run a LOT of JS before your browser paints anything, but you should avoid doing too much or you’ll end up dropping frames, or breaking the “illusion”. Run the el.animate in the full snippet within a setTimeout with a time of 16.7 or so and you’ll see what I mean.)

Then we’ll calculate the positional and scale differences in some way.

const deltaX = first.left - last.left;
const deltaY = first.top - last.top;
const deltaW = first.width / last.width;
const deltaH = first.height / last.height;

The last two phases, Invert, and Play can be done with one API. The WebAnimations API.

// Use the WebAnimations API to make the element appear at the "first" phase by transforming it according to the offsets
el.animate(
  [
    {
      transformOrigin: 'top left',
      transform: `translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`,
    },
    // And then animate it to the "last", or current place by basically disabling the transformed offsets
    {
      transformOrigin: 'top left',
      transform: 'none',
    },
  ],
  {
    duration: 250,
    easing: 'ease-in-out',
  }
);

Element.animate accepts an array of Key-Frames.

We use the first key-frame to specify the “Invert” phase. We do that by transforming the element by translating it by the positional offsets that we calculated, and the scale differences that we calculated to make it appear the same size and in the same place at the “First” phase.

In the next Key-Frame, we basically turn off the transforms, making it animate into it’s actual position and size, triggering the “Play” phase, and concluding the animation. Obviously we specify an animation duration, and optionally an easing function.

This sums up what FLIP does. But it has a problem.
If there are any children that may need to be the same size and in the same place, they will be “raster-scaled” with the parent, making it look pretty odd.

How children will look like immediately after the animation is triggered to make the element smaller
How children will look like immediately after the animation is triggered to make the element smaller
How the children should look like immediately after the animation is triggered
How the children should look like immediately after the animation is triggered

This requires a pretty simple fix, at least in my experiment where the children are guaranteed to be centered, eliminating some position related problems. The fix we have to write will be for the scale.

The most common-sense approach to this that I could think of (and that some others also mention) is that animate the childrens scale inversely with the parent. So if the parent is going big-to-small based on some first/last parameter, we’ll animate the child based on a last/first parameter. Lo and behold, that is exactly what I’ve done.

const parentDeltaW = parentFirst.width / parentLast.width;
const parentDeltaH = parentFirst.height / parentLast.height;

// Get scale offset for the parent, because we want the child to scale inversely to the parent
const childDeltaW = parentLast.width / parentFirst.width;
const childDeltaH = parentLast.height / parentFirst.height;

Source for this, if you want to take a look: https://github.com/jayantbh/experiments/blob/master/src/components/FlipAnimationTechnique/hooks/use-child-aware-animation.ts#L33-L40

This concludes this experiment on FLIP animations.

This thing is crazy. This allows you to “fake” performant animations with left and all based property changes. This would make so many use-cases where you struggle to get a nice animation experience simply because the page has so much going on, easy to achieve well.

Here’s some stuff I read, and borrowed a lot from.

https://reactjs.org/docs/hooks-reference.html

https://popmotion.io/pose/learn/flip/

Clip Path Route Transitions

Clip Path Route Transitions

View/page transitions done in a bit of a new way, using the CSS clip-path property. Here I’ll discuss the clip-path property and route transitions using this property. tl;dr: See the experiment at https://jayant.dev/experiments/clip-path-route, and be cautious of render performance if you do this. Anyone reading 

An experiment with CSS Animations

An experiment with CSS Animations

If you want performant animations, you go with CSS Transforms. – almost everyone, 2019 This is an experiment with CSS Animations that you can try out yourself at https://jayant.dev/experiments/animation-comparisons. CSS Transforms are more performant than animating non-transform properties (like left or height, etc.), that’s what 

Samsung Galaxy Grand Duos GT I-9082 User Review

Hey people! I thought about writing this long ago, but a little late isn’t that bad, is it.

Now, why should you read this review? Well, there are a gazillion reviews out there, but none written by someone do restricted on budget like me! So here I go.

There are some lower budget phones in the market that claim to deliver way better performance than the grand, I call it bullshit! One fundamental thing you must keep in mind, newer hardware is always better than old hardware. And the hardware on the Canvas 2 is old, regardless of the phone being new.

Starting with the display, the ppi might look low to those who have used high end phones before. But the point is, if you’ve bought a 30k phone before, why the hell would you want the grand? I automatically assume that you’re rich enough to buy a better smartphone. And if you’re the poor man, like me, this is your poor man’s Galaxy S3! A 5 inch tool is what a lot of men don’t have!

So the ppi… it doesn’t bother me, it is nice enough for everything! Multimedia, gaming, browsing, etc.

Performance wise, it’s great! Regardless of what benchmarks say(though the benchmark scores, tested by myself using multiple benchmarking apps, are impressive!) the grand does great! And it blows away competition in Nenamark 2! It can play almost every game! Mind it, I said almost. Though the grand will act erratically occasionally to remind you of the difference between a flagship and it, but it still didn’t bother me. It still remains reliable considering I use it nicely. Nicely doesn’t mean that I don’t use many apps. Already having 124 apps, and still got space!

Obviously it has expandable storage capability, and 4GB of internal memory isn’t a headache for me. I have a 16GB SD card. I store my data there. So stop crying about internal memory.

The user interface is good, multi window is very handy at times! For example, I can text message someone while texting another guy on Facebook without switching applications! (Now we have the chat heads feature, but you get the point.)

The battery doesn’t disappoint, lasts long enough. Plus, the phone doesn’t even heat! At least not irritably!

The cameras, 8 and 2 mp each with full HD recording capability and ZERO SHUTTER LAG show you to take amazing pictures, and especially videos! Damn! Ask me! I’m more of a multimedia guy!

The phone does feel plasticky though, and gave me a scare when I was opening the back cover for the first time! It’s totally plastic, solid plastic though, but I thought it’d break! It didn’t break. The flip cover is classic, I think it’s not so useless, it’s good.

Vodafone users, put your old SIM into this and get 2GB free data! It’s a good deal!

This phone won’t let down a person limited on budget.

But if you’re into android development and can’t live without tweaking it, dump this phone. It’s got close to nil development right now. If you want to know anything and everything about this phone, mail me or comment below.

Thanks for your time.