Reputation: 650
I try to use a library Tick, but it only has a demo, which is written in React class component.
import React from "react";
import Tick from "@pqina/flip";
import "@pqina/flip/dist/flip.min.css";
export default class Flip extends React.Component {
constructor(props) {
super(props);
this._tickRef = React.createRef();
}
componentDidMount() {
this._tickInstance = Tick.DOM.create(this._tickRef.current, {
value: this.props.value
});
}
componentDidUpdate() {
if (!this._tickInstance) return;
this._tickInstance.value = this.props.value;
}
componentWillUnmount() {
if (!this._tickInstance) return;
Tick.DOM.destroy(this._tickRef.current);
}
render() {
return (
<div ref={this._tickRef} className="tick">
<div data-repeat="true" aria-hidden="true">
<span data-view="flip">Tick</span>
</div>
</div>
);
}
}
I'd like to use the library as a Hook component, the following code is what I rewritten:
import Tick from "@pqina/flip";
import "@pqina/flip/dist/flip.min.css";
import React, { useEffect, useRef, useState } from 'react';
interface IFilpProps {
value: number
}
const Filp: React.FC<IFilpProps> = (props) => {
const ref = useRef<HTMLDivElement>(null);
const [tickInstance, setTickInstance] = useState<any>();
useEffect(() => {
setTickInstance(Tick.DOM.create(ref.current, {
value: props.value
}));
return () => {
Tick.DOM.destroy(ref.current);
}
}, []);
useEffect(() => {
tickInstance?.value && (tickInstance.value = props.value);
}, [props.value])
return <div ref={ref} className="tick">
<div data-repeat="true" aria-hidden="true">
<span data-view="flip">Tick</span>
</div>
</div>
}
outside the component, I have a button, every time I click it adds one:
const [flipSecond, setFlipSecond] = useState<number>(0);
// Omit some not important code
<Flip value={flipSecond}></Flip>
<button onClick={() => setFlipSecond(flipSecond+1)}>+1</button>
The demo which uses class component works fine, but my hook code can't work normally: when I click the '+1' button, the Flip component won't plus 1. Could you help me find out the the reason?
Upvotes: 0
Views: 299
Reputation: 23
This is a rewrite for the historic counter
Eg. Counts the time passed since the start of the millenium in years, months, days, hours, minutes and seconds.
The main thing to take away from here is the use of useRef()
and how we are using it when creating the tickInstance
with Tick.DOM.create()
const FlipClock = () => {
const tickRef = useRef();
useEffect(() => {
const tickInstance = Tick.DOM.create(tickRef.current);
Tick.count.up("2000-01-01T00:00:00",
{format: ["y", "M", "d", "h", "m", "s"],})
.onupdate = (value) => {
tickInstance.value = value;
};
});
return (
<div ref={tickRef} style={{ fontSize: "3rem" }}>
<div data-repeat="true" aria-hidden="true">
<span data-view="flip">Tick</span>
</div>
</div>
);
};
export default FlipClock;
Upvotes: 0
Reputation: 14570
You should use a ref instead of state to store tickInstance
.
In general if you want to replace variables that used to be stored in the constructor before, it is recommended now to be stored as refs when rewriting class based components to functional.
export default function Flip({value}) {
const tickRef = React.useRef();
let tickInstance = React.useRef()
useEffect(()=>{
tickInstance.current = Tick.DOM.create(tickRef.current, {
value
});
return () => Tick.DOM.destroy(tickRef.current);
},[])
useEffect(()=>{
if (!tickInstance.current) return;
tickInstance.current.value = value;
},[value])
return (
<div ref={tickRef} className="tick">
<div data-repeat="true" aria-hidden="true">
<span data-view="flip">Tick</span>
</div>
</div>
)
}
Upvotes: 2