将 React 类组件重写为功能组件

时间:2021-01-29 18:23:28

标签: javascript reactjs typescript

我尝试使用库 Tick,但它只有一个 demo,它是用 React 类组件编写的。

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

我想用这个库作为一个Hook组件,下面是我改写的代码:

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

在组件外,我有一个按钮,每次点击添加一个:

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 工作正常,但是我的hook代码不能正常工作:当我点击'+1'按钮时,Flip组件不会加1。你能帮我找出原因吗?

2 个答案:

答案 0 :(得分:2)

您应该使用 ref 而不是 state 来存储 tickInstance。 一般来说,如果你想替换之前存储在构造函数中的变量,现在建议在将基于类的组件重写为函数式时将其存储为 refs。

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

答案 1 :(得分:0)

这是对历史计数器的重写

例如。 以年、月、日、小时、分钟和秒为单位计算千禧年开始以来经过的时间。

这里要讲的主要内容是 useRef() 的使用以及我们在使用 tickInstance 创建 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