@stkterry/react-reanim
Simplify HTML5 canvas animations in React!
This project has two primary goals:
- Prevent React from constantly re-rendering when drawing to the canvas. Essentially, turn the canvas into a mostly static component.
- Separate the step / draw functionality from the associated boiler-plate common to virtually every canvas animation.
Install
npm install --save @stkterry/react-reanim
Usage
The following results in a simple, spinning cube as a basic example.
import React, { Component } from 'react'
import Reanim from '@stkterry/react-reanim'
export default function Simple() {
const [angle, setAngle] = useState(0);
const [style, setStyle] = useState();
useEffect(() => {
setStyle({ width: "250px", height: "250px",});
}, [])
const step = () => setAngle(angle + 1);
const draw = ctx => {
const width = ctx.canvas.width;
const height = ctx.canvas.height;
ctx.save();
ctx.beginPath();
ctx.clearRect(0, 0, width, height);
ctx.translate(width / 2, height / 2);
ctx.rotate(angle * Math.PI / 180);
ctx.fillStyle = '#4397AC';
ctx.fillRect(-width / 4, -height / 4, width / 2, height / 2);
ctx.restore();
};
return (
<Reanim
step={step}
draw={draw}
width="250px"
height="250px"
style={style}
/>
)
}
Reanim Options
Name | Type | Description | Default |
---|---|---|---|
step | function | Animation step, updated each frame | REQUIRED | |
draw | function | Drawn to canvas each frame, must be written to include a canvas context input | REQUIRED | |
onClick | function | Normal 'onClick' functionality, automatically gets memoized* | |
onClickVars | function | onClick variables that you want to trigger a re-render when onClick is called* | [ ] |
run | boolean | Starts/stops the animation loop | true |
useCallback(yourOnClickFunction, [...onClickVars])
Reanim will accept any other attributes that are common to React/canvas and pass
them accordingly (className, onMouseOver, style, width, height, etc...).
Important!
If you pass functions or objects to Reanim (excluding step/draw/onClick) without wrapping them in a useCallback or otherwise effectively memoizing them, you will trigger re-renders of the component on every frame! While not necessarily a problem, this can/will affect performance! I'm working on a solution that will auto-memoize commonly passed variables.
Other
Common canvas weirdness still applies to Reanim. It's up to you to know how to wield HTML5 canvas effectively. This component is just a wrapper to separate the step/draw functions from the typical boiler-plate necessary to get a canvas up and running.
Canvas
If you so desire, you can make use of the inner canvas component directly.
import React, { useState } from 'react';
import { Canvas } from '@stkterry/react-reanim';
export default function Example(props) {
// ... some code here
// ...
// ...
const [ctx, setCtx] = useState();
// do something with ctx
return (
<Canvas setCtx={setCtx} />
)
};
Note that the only variable Canvas requires is a setCtx function which should assign a 2d context off the node when mounted, otherwise Canvas will accept anything your standard canvas will. Canvas is memoized by default but remember that the contents you pass it may constantly trigger re-renders anyway.
Canvas is just a memoized regular canvas element with a passback for setting context.
Bonus Hooks!
useWindowDims
This hook returns the inner width and height of the current window. It's lightweight and will automatically add/remove the event listener. Updates on resize.
import React from 'react';
import { useWindowDims } from '@stkterry/react-reanim';
export default function Example(props) {
const windowDims = useWindowDims();
return (
<div>
<h2>innerWidth: {windowDims.width}</h2>
<h2>innerHeight: {windowDims.height}</h2>
</div>
)
}
You may find this useful if you need to dynamically style or control your canvas based on window size.
To Do
- Add target frame-rate functionality
- Add collection of convenient hooks for working with the canvas
- Implement a context simplification library for drawing
- Add real tests...
License
MIT © stkterry