简体   繁体   中英

Rewrite a react class component as a functional component

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?

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>
  )
}

Demo

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;

Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM