useCounter hook with Framer Motion
useCounter Hook
import * as React from "react";
import { animate, useInView } from "framer-motion";
function useCounter({ from = 0, to, duration }) {
const ref = React.useRef(null);
const isInView = useInView(ref, {
once: true,
});
const [value, setValue] = React.useState(from);
React.useEffect(() => {
if (!isInView) {
return;
}
const controls = animate(from, to, {
duration,
onUpdate(value) {
setValue(value);
},
});
return () => controls.stop();
}, [isInView, from, to, duration]);
return {
ref,
count: Intl.NumberFormat().format(value.toFixed(0)),
};
}
import * as React from "react";
import { animate, useInView } from "framer-motion";
function useCounter({ from = 0, to, duration }) {
const ref = React.useRef(null);
const isInView = useInView(ref, {
once: true,
});
const [value, setValue] = React.useState(from);
React.useEffect(() => {
if (!isInView) {
return;
}
const controls = animate(from, to, {
duration,
onUpdate(value) {
setValue(value);
},
});
return () => controls.stop();
}, [isInView, from, to, duration]);
return {
ref,
count: Intl.NumberFormat().format(value.toFixed(0)),
};
}
Usage
import useCounter from "hooks/useCounter";
export default function App() {
const { ref, count } = useCounter({
from: 0,
to: 1000,
duration: 2,
});
return (
<div className="App">
<p ref={ref}>{count}</p>
</div>
);
}
import useCounter from "hooks/useCounter";
export default function App() {
const { ref, count } = useCounter({
from: 0,
to: 1000,
duration: 2,
});
return (
<div className="App">
<p ref={ref}>{count}</p>
</div>
);
}
View demo.