005 - Setting up Anime.js

Date: June 2nd 2020

Experimenting with SVG manipulation and animation in order to prepare for making my final project. My goals and tasks include:

anime.js

Installed anime.js into my package.json through npm

npm install animejs --save

followed by importing it into this functional components

import anime from 'animejs';

Lets try move some squares around the place

For this, i had to create a class based component for the box that toook in the props for the translateX. This was then rendered during componentDidMount and componentDidUpdate through a this.anime function. The click action was then taken care of by a button on the page (also a class based component) that updated its state which was passed to the Box component.

Added another class and then used the same button to effect its movement but in a different way. When updating the props I ran into an issue with typescript that it didn't recognize the this.box reference. I'm not sure how to fix this but will ask Peter. This will also be a key issue when wanting to make new objects on click and each one having a seperate ref

The problem I see with this current version is that the state is currently being help on the page component, and I need each object to have its own stored state and then for the top level to controll how many of these there are.


After Chatting with Peter

After a long chat with Peter about using Typescript with anime.js I've made some big changes to how to write the components for this. The main difference is to use pure Functional Components for the objects and then dealing with the anime() in the useEffect.

const Box2 = ({ translateX, translateY, initX, initY }: BoxProps) => {
  const ref = React.useRef<HTMLDivElement>(null);
  React.useEffect(() => {
    const instance = anime({
      targets: ref.current,
      translateX: { value: translateX + initX },
      translateY: { value: translateY + initY },
      duration: 20000,
    });
    return instance.pause;
  }, [translateX, translateY, initX, initY]);

  return (
    <div
      ref={ref}
      style={{
        height: 50,
        width: 50,
        backgroundColor: "tomato",
        transform: "translateX(500px)",
      }}
    ></div>
  );
};

Here is a box made from a 'pure' functional component

Peter also suggested ways to clean up the state managment system. Suggesting that there should be a BoxManagement component that uses hooks to manage an array of boxes that holds the id's and internal states of each box. Then each box can be be rendered using map.


        interface BoxManagerState {
            boxes: Array<{id: string, state: 'default' | 'fadeOut'}>
        }
        
        const BoxManager = () => {
            const [state, setState] = React.useState<BoxManagerState>({
                boxes: []
            })
            const actions = React.useMemo(() => ({
             removeBox: (id: string) => setState({
                 ...state, 
                 boxes: state.boxes.filter(x => x.id === id)})
            }), [])
        
            return state.boxes.map(x => 
                <Box2 
                    key={x.id}  
                    id={x.id} 
                    actions={actions} 
                    onComplete={() => 
                        actions.removeBox(x.id)} 
                    style={x.state} />)
        }