Categories
React

Add Animation with the react-awesome-reveal Library

With the react-awesome-reveal library, we can render animations in our React app easily.

In this article, we’ll take a look at how to get started with the react-awesome-reveal.

Installation

We can install the library by running:

npm install react-awesome-reveal --save

with NPM or we can run:

yarn add react-awesome-reveal

with Yarn.

Quick Start

We can add a simple fade effect to our content with the Fade component.

For example, we can write:

import React from "react";
import { Fade } from "react-awesome-reveal";

export default function App() {
  return (
    <div className="App">
      <Fade>
        <p>hello world</p>
      </Fade>
    </div>
  );
}

to display ‘hello world’ with a fade effect as it enters.

Other supported effects include Bounce, Fade, Flip, Hinge, JackInTheBox, Roll, Rotate, Slide and Zoom .

We can add the triggerOnce prop to animate only the first time an element enters the viewport:

import React from "react";
import { Fade } from "react-awesome-reveal";

export default function App() {
  return (
    <div className="App">
      <Fade triggerOnce>
        <p>hello world</p>
      </Fade>
    </div>
  );
}

Chaining Multiple Animations

We can chain multiple animations with the cascade prop:

import React from "react";
import { Fade } from "react-awesome-reveal";

export default function App() {
  return (
    <div className="App">
      <Fade cascade>
        <p>foo</p>
        <p>bar</p>
        <p>baz</p>
      </Fade>
    </div>
  );
}

Then each of the p elements will be animated one after the other.

This is similar to:

import React from "react";
import { Fade } from "react-awesome-reveal";

export default function App() {
  return (
    <div className="App">
      <Fade>
        <p>foo</p>
      </Fade>
      <Fade delay={1000}>
        <p>bar</p>
      </Fade>
      <Fade delay={2000}>
        <p>baz</p>
      </Fade>
    </div>
  );
}

except that cascade shows the 2nd item only after the first enter the viewport.

Custom Animations

We can create custom animations with the keyframes tag.

For example, we can write:

import React from "react";
import Reveal from "react-awesome-reveal";
import { keyframes } from "[@emotion/core](https://medium.com/r/?url=http%3A%2F%2Ftwitter.com%2Femotion%2Fcore "Twitter profile for @emotion/core")";

const customAnimation = keyframes`
  from {
    opacity: 0;
    transform: translate3d(200px, 100px, 0);
  }

to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
`;

function AnimatedComponent({ children }) {
  return <Reveal keyframes={customAnimation}>{children}</Reveal>;
}

export default function App() {
  return (
    <div className="App">
      <AnimatedComponent>
        <p>hello world</p>
      </AnimatedComponent>
    </div>
  );
}

to create the customAnimation object with the keyframes tag.

We specify the from styles that are rendered at the start of the animation.

The to styles are rendered at the end of the animation.

The styles in between are interpolated.

Then we can use that with the Reveal component’s keyframes prop.

And we use our AnimatedComponent in the App component.

If no keyframes prop is passed in, the default rendered animation is fade entrance from the left.

Other props we can pass to Reveal include:

  • cascade
  • damping
  • delay
  • duration
  • fraction
  • triggerOnce
  • className and childClassName
  • style and childStyle

Conclusion

We can add simple animation with the react-awesome-real library.

Categories
Vue 3

Vue 3 — Props Data Flow

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at how to use props with Vue 3.

One-Way Data Flow

Props have a one way downward binding between the parent and child component.

When the parent property updates, then the updates are passed into the child via props.

This prevents child components from accidentally mutating the parent’s state.

And this makes our app easier to understand.

We should never mutate props.

If we need to change their value, then we should assign them to a new property first.

For instance, if we need to change the value of an initial value that’s set with the prop’s value, then we should assign that to a state first.

So we should write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <counter :initial-count="5"></counter>
    </div>
    <script>
      const app = Vue.createApp({}); app.component("counter", {
        props: ["initialCount"],
        data() {
          return {
            count: this.initialCount
          };
        },
        template: `
          <div>
            <button @click='count++'>increment</button>
            <p>{{count}}</p>
          </div>
        `
      }); app.mount("#app");
    </script>
  </body>
</html>

We have the initialCount prop that we use to set the initial value of count state in the counter component.

Then we can do whatever we like with it.

If the value needs to be transformed, then we can put it in as a computed property.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <counter :initial-count="5"></counter>
    </div>
    <script>
      const app = Vue.createApp({}); 
      app.component("counter", {
        props: ["initialCount"],
        data() {
          return {
            count: this.initialCount
          };
        },
        computed: {
          doubleCount() {
            return this.count * 2;
          }
        },
        template: `
          <div>
            <button @click='count++'>increment</button>
            <p>{{doubleCount}}</p>
          </div>
        `
      }); app.mount("#app");
    </script>
  </body>
</html>

We have the initial-count prop which is transformed to doubleCount by returning this.count * 2 .

Now we don’t have to do anything with the prop value itself.

And we just change the state to what we want within the data method and the computed property in the counter component.

Prop Validation

We can validate props by check its data type and more.

We set the the props property’s value to a constructor.

Or we can validate it with a function.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <blog-post v-for="post of posts"></blog-post>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            posts: [{ author: "james", likes: 100 }]
          };
        }
      });
      app.component("blog-post", {
        props: {
          title: {
            type: String,
            default: "default title"
          }
        },
        template: `<p>{{title}}</p>`
      });
      app.mount("#app");
    </script>
  </body>
</html>

Then we get the ‘default title’ text displayed since we never passed in value to the title prop.

default has the default value.

validator has the validator function for props.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <blog-post v-for="post of posts" type="news"></blog-post>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            posts: [{ author: "james", likes: 100 }]
          };
        }
      });
      app.component("blog-post", {
        props: {
          type: {
            validator(value) {
              return ["news", "announcement"].indexOf(value) !== -1;
            }
          }
        },
        template: `<p>{{type}}</p>`
      });
      app.mount("#app");
    </script>
  </body>
</html>

to add a validator for the type prop.

The validator method is run when we pass in the prop with the given name.

The value is the value that we pass in.

So if we pass in something other than 'new' or 'announcement' like:

<blog-post v-for="post of posts" type="foo"></blog-post>

then we’ll get a warning.

We can also add the required property and set it to true to make a prop required like:

prop: {
  type: String,
  required: true
}

Conclusion

We can validate props with constructors and validation functions.

Also, we can add the default property to set the default value of a prop.

Categories
React

Animation with the react-tweenful Library — SVG Animation

With the react-tweenful library, we can render animations in our React app easily.

In this article, we’ll take a look at how to get started with the react-tweenful.

SVG Animation

We can add animations to SVGs with the SVG object.

For example, we can write:

import React from "react";
import { SVG, percentage, elastic } from "react-tweenful";

const circles = new Array(5).fill(0).map((_e, i) => ({
  loop: true,
  fill: `hsl(${(i + 1) * 20 - 20}, 70%, 70%)`,
  delay: ((i + 1) * 1500) / -10,
  duration: 1500,
  easing: elastic(2, 0.9),
  transform: {
    translate: "0 100px"
  },
  style: {
    transformOrigin: `${-200 + 120 * (i + 1)}px 250px`
  },
  animate: percentage({
    "0%": { translate: "0px 100px", scale: 1 },
    "50%": { translate: "0px -100px", scale: 0.3 },
    "100%": { translate: "0px 100px", scale: 1 }
  }),
  r: 35,
  cx: 100 * i + 50,
  cy: 250
}));

export default function App() {
  return (
    <div className="bouncing-balls">
      <svg
        xmlns="http://www.w3.org/2000/svg"
        x="0px"
        y="0px"
        viewBox="0 0 1000 500"
      >
        {circles.map((circle, i) => (
          <SVG.circle key={i} {...circle}></SVG.circle>
        ))}
      </svg>
    </div>
  );
}

to add a bouncing ball effect.

The circles array has objects which are created with styles that we apply to create the bouncing ball effect.

fill has the fill color.

loop set to true means we repeat the animation forever.

delay has the animation delay.

duration has the duration of the animation.

easing has the easing of the animation.

transform is the CSS transform property.

style has more styles we apply.

animate lets us add styles applied at the given progress for the animation.

r , cx , and cy have the radius, and the x and y coordinates of the center of the circle respectively.

In the JSX, we create the svg component with the SVG.circle components inside it.

We apply all the animation styles by spreading the circle properties that we created earlier.

Now we should see the bouncing ball effect displayed.

Conclusion

We can animate SVGs easily with the react-tweenful library.

Categories
React

Animation with the react-tweenful Library — Gradients and Rotation

With the react-tweenful library, we can render animations in our React app easily.

In this article, we’ll take a look at how to get started with the react-tweenful.

Gradients

We can add gradients animations with react-tweenful.

For example, we can write:

App.js

import React from "react";
import Tweenful, { elastic } from "react-tweenful";
import "./styles.css";

export default function App() {
  const elements = new Array(5)
    .fill(0)
    .map((_e, i) => (
      <Tweenful.div
        className={`gradient${i + 1} box`}
        loop={true}
        easing={elastic(1, 0.1)}
        duration={3000}
        delay={i * 100}
        endDelay={(10 - i) * 100}
        animate={[{ height: "20%" }, { height: ["20%", "auto"] }]}
        key={i}
      ></Tweenful.div>
    ));

  return (
    <div className="gradients-container">
      <div className="row">{elements}</div>
    </div>
  );
}

styles.css

.row {
  display: flex;
  flex-direction: row;
}

.gradient1.box {
  background-color: #fafa6e;
  height: 100px;
  width: 50px;
}

.gradient2.box {
  background-color: #d7f171;
  height: 100px;
  width: 50px;
}

.gradient3.box {
  background-color: #b5e877;
  height: 100px;
  width: 50px;
}

.gradient4.box {
  background-color: #95dd7d;
  height: 100px;
  width: 50px;
}

.gradient5.box {
  background-color: #77d183;
  height: 100px;
  width: 50px;
}

We create the elements with an array and map those to the Tweenful.div component.

We set the className of the div.

We set loop to true to loop the animation indefinitely.

easing has the easing function to apply.

delay has the start delay for the animation.

endDelay has the end delay duration for the animation.

animate has an array with the styles applied at the start of the animation and at the end respectively.

Then we render all that in the JSX.

In styles.css , we set the styles for the divs.

Rotation

We can add keyframes with react-tweenful to create more complex animations.

For example, we can write:

App.js

import React from "react";
import Tweenful, { percentage } from "react-tweenful";
import "./styles.css";

const rotate = percentage({
  "0%": { translate: "-50% -50%", rotate: "0deg" },
  "50%": { translate: "-50% -50%", rotate: "0deg" },
  "80%": { translate: "-50% -50%", rotate: "360deg" },
  "100%": { translate: "-50% -50%", rotate: "360deg" }
});
const dot1Animate = percentage({
  "0%": { scale: 1 },
  "20%": { scale: 1 },
  "45%": { translate: "16px 12px", scale: 0.45 },
  "60%": { translate: "160px 150px", scale: 0.45 },
  "80%": { translate: "160px 150px", scale: 0.45 },
  "100%": { translate: "0px 0px", scale: 1 }
});
const dot2Animate = percentage({
  "0%": { scale: 1 },
  "20%": { scale: 1 },
  "45%": { translate: "-16px 12px", scale: 0.45 },
  "60%": { translate: "-160px 150px", scale: 0.45 },
  "80%": { translate: "-160px 150px", scale: 0.45 },
  "100%": { translate: "0px 0px", scale: 1 }
});
export default function App() {
  return (
    <div className="loading-wrapper">
      <Tweenful.div
        className="loading-circles-container"
        duration={2000}
        loop={true}
        easing="easeInOutCubic"
        transform={{ translate: "-50% -50%" }}
        animate={rotate}
      >
        <Tweenful.div
          className="dot dot-1"
          duration={2000}
          easing="easeOutCubic"
          loop={true}
          transform={{ translate: "0px 0px", scale: 1 }}
          animate={dot1Animate}
        ></Tweenful.div>
        <Tweenful.div
          className="dot dot-2"
          duration={2000}
          easing="easeOutCubic"
          loop={true}
          transform={{ translate: "0px 0px", scale: 1 }}
          animate={dot2Animate}
        ></Tweenful.div>
      </Tweenful.div>
    </div>
  );
}

styles.css

.dot.dot-1 {
  background-color: red;
  width: 40px;
  height: 40px;
  border-radius: 50%;
}

.dot.dot-2 {
  background-color: green;
  width: 40px;
  height: 40px;
  border-radius: 50%;
}

We have the rotate , dot1Animate , and dot2Animate object that has the animation progress as the keys and the styles to apply at the given progress as the value.

We translate and rotate the elements that has the animate prop set to these objects.

In the Tweenful.div components, we set the transform prop to transform the items more.

We also set the easing and set loop to true to repeat the animation forever.

In styles.css , we add the styles for the divs.

Now we should see 2 rotating divs.

Conclusion

We can add gradients and rotation with react-tweenful.

Categories
React

Animation with the react-tweenful Library — Observers

With the react-tweenful library, we can render animations in our React app easily.

In this article, we’ll take a look at how to get started with the react-tweenful.

ObserverGroup

We can use the ObserverGroup component to watch for mounting and unmounting over a list of notifications.

For example, we can use it by writing:

import React, { useState } from "react";
import { ObserverGroup } from "react-tweenful";

const items = [
  { text: "foo", id: 1 },
  { text: "bar", id: 2 },
  { text: "baz", id: 3 }
];

export default function App() {
  const [notifications, setNotifications] = useState(items);

const removeNotification = (id) => {
    setNotifications((notifications) =>
      notifications.filter((n) => n.id !== id)
    );
  };

  return (
    <ObserverGroup
      config={{
        duration: 800,
        style: { overflow: "hidden" },
        mount: { opacity: [0, 1], height: ["0px", "auto"] },
        unmount: { opacity: [1, 0], height: ["auto", "0px"] },
        easing: "easeInOutCubic"
      }}
      skipInitial={true}
    >
      {notifications.map((notification) => (
        <div
          key={notification.id}
          onClick={removeNotification.bind(undefined, notification.id)}
        >
          {notification.text}
        </div>
      ))}
    </ObserverGroup>
  );
}

We have an items array which we use as the initial value of the notifications state.

Next, we add the removeNotification function that takes an id and removes the entry with the given id .

In the JSX, we use the ObserverGroup component to define our animation.

The config prop has various properties we set to add the animation.

duration has the duration of the animation.

style has style for the container.

mount has the styles to apply when we mount a component inside the ObserverGroup.

unmount has the styles to apply when we unmount a component inside the ObserverGroup .

The easing property has the easing function to apply.

skipInitial skips animation when the components loads when it’s set to true .

Now when we click on the div for the notifications entry, we should see the animation displayed.

Animate Route Transition

We can use react-tweenful to animate route transition.

For example, we can write:

App.js

import React from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import { ObserverGroup, Observer } from "react-tweenful";
import "./styles.css";

const colors = {
  red: "#EE4266",
  yellow: "#FDB833",
  blue: "#296EB4",
  green: "#0EAD69"
};

const observerProps = {
  className: "key-wrapper",
  duration: 1000,
  style: { opacity: 0 },
  mount: { opacity: 1 },
  unmount: { opacity: 0 },
  easing: "easeOutQuad"
};

const Red = () => (
  <ObserverGroup>
    <Observer.div {...observerProps}>
      <div
        className="color-block"
        style={{ backgroundColor: colors.red }}
      ></div>
    </Observer.div>
  </ObserverGroup>
);
const Yellow = () => (
  <ObserverGroup>
    <Observer.div {...observerProps}>
      <div
        className="color-block"
        style={{ backgroundColor: colors.yellow }}
      ></div>
    </Observer.div>
  </ObserverGroup>
);
const Blue = () => (
  <ObserverGroup>
    <Observer.div {...observerProps}>
      <div
        className="color-block"
        style={{ backgroundColor: colors.blue }}
      ></div>
    </Observer.div>
  </ObserverGroup>
);
const Green = () => (
  <ObserverGroup>
    <Observer.div {...observerProps}>
      <div
        className="color-block"
        style={{ backgroundColor: colors.green }}
      ></div>
    </Observer.div>
  </ObserverGroup>
);

export default function App() {
  return (
    <div>
      <Router>
        <ul className="nav-links">
          <li>
            <Link to="/transition/red">Red</Link>
          </li>
          <li>
            <Link to="/transition/yellow">Yellow</Link>
          </li>
          <li>
            <Link to="/transition/blue">Blue</Link>
          </li>
          <li>
            <Link to="/transition/green">Green</Link>
          </li>
        </ul>
        <Switch>
          <Route exact path={`/transition/red`}>
            <Red />
          </Route>
          <Route exact path={`/transition/green`}>
            <Green />
          </Route>
          <Route exact path={`/transition/blue`}>
            <Blue />
          </Route>
          <Route exact path={`/transition/yellow`}>
            <Yellow />
          </Route>
        </Switch>
      </Router>
    </div>
  );
}

styles.css

.color-block {
  width: 100px;
  height: 100px;
}

We create the Red , Green , Blue , and Yellow components which we use as the route components.

We add them in between the Route components to use them as such.

Each of the component has the ObserverGroup and the Observer.div component to let us apply the animation effects specified in the observerProps object.

The colors object values are used in the same components to add colors.

We also have styles.css to change the size of the boxes in those components.

The Link component lets us load the routes when we click on the links.

Now we should see the boxes displayed with the color, and when they mount, we should see the transition.

Conclusion

We can use the ObserverGroup component to add transitions to groups of elements.

React-tweenful also works with React Router.