Search code examples
javascriptreactjsref

Having trouble converting HTML to React specific code. I am using `@pqina/flip`?


I am using https://github.com/pqina/flip & want to implement Tick.count.down() method using React. There's no React specific code that is given in the example & also the author is swamped so thought I'd ask here for some React experts.

I've cloned the above repo & replaced https://github.com/pqina/flip/tree/master/example/index.html contents with the following code.

I have the following HTML working perfectly:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width" />
        <title>Count Down</title>

        <link rel="stylesheet" href="../dist/core/tick.core.min.css" />
    </head>
    <body>
        <style>
            .tick {
                font-size: 2rem;
            }
        </style>

        <p>Countdown from 10</p>
        <div class="tick" data-did-init="startNumericCountdown">
            <span data-view="text"></span>
        </div>

        <script>
            function startNumericCountdown(tick) {
                console.log(`start numeric countdown...`)
                var counter = Tick.count.down(10, 'seconds')
                counter.onupdate = function (value) {
                    tick.value = value
                }
                counter.onended = function () {
                    console.log(`countdown over 😟`)
                }
            }
        </script>

        <script src="../dist/core/tick.core.kickstart.min.js"></script>
    </body>
</html>

The problem comes when I try to convert it into React. Currently, I have the following code:

import React, { useRef, useEffect } from "react";
import Tick from "@pqina/flip";
import "@pqina/flip/dist/flip.min.css";

export const FlipDate = ({ value }) => {
  const divRef = useRef();
  const tickRef = useRef();

  useEffect(() => {
    const didInit = tick => {
      console.log("didInit");

      console.log({ tick });
      tickRef.current = tick;
    };

    const currDiv = divRef.current;
    const tickValue = tickRef.current;
    Tick.DOM.create(currDiv, {
      value: Tick.count.down(10, 'seconds'),
      didInit
    });
    // divRef.current = Tick.count.down(10, 'seconds');

    return () => Tick.DOM.destroy(tickValue);
  });

  useEffect(() => {
    console.log({ tickRef });
    if (tickRef.current) {
      console.log({ divRef });
      tickRef.current.value = value;
    }
  }, [value]);

  return (
    <div ref={divRef} className="tick">
      <div data-repeat="true">
        <span data-view="flip">Tick</span>
      </div>
    </div>
  );
};

This does not work as expected. I've got the basic flip library working as you can see in my demo here: https://codesandbox.io/s/react-flip-countdown-timer-8tin3?file=/src/App.js

3 of the files are the same code: 1 being using class component Flip.js, 2 using Hooks Flipr.js & Flippen.js.

I want to make FlipDate.js working. It should count down from 10 seconds to 0 seconds. Been trying this for the last week but couldn't wrap my head around this. Any help is appreciated 🙏

Sidenote: https://github.com/pqina/flip uses https://github.com/pqina/tick underhood.


Solution

  • I posted the same question on Reddit at /r/reactjs as well & found the answer there. Here's a working solution:

    import React, { useRef, useEffect, useState } from "react";
    import Tick from "@pqina/flip";
    import "@pqina/flip/dist/flip.min.css";
    
    export const WorkingFlipDate = ({ value }) => {
      const divRef = useRef();
      const tickRef = useRef();
    
      const [tickValue, setTickValue] = useState(value);
    
      // Make the Tick instance and store it in the refs
      useEffect(() => {
        const didInit = tick => {
          tickRef.current = tick;
        };
    
        const currDiv = divRef.current;
        const tickValue = tickRef.current;
        Tick.DOM.create(currDiv, {
          value,
          didInit
        });
        return () => Tick.DOM.destroy(tickValue);
      }, [value]);
    
      // Start the Tick.down process
      useEffect(() => {
        const counter = Tick.count.down(value, {
          format: ["d", "h", "m", "s"]
        });
    
        // When the counter updates, update React's state value
        counter.onupdate = function(value) {
          setTickValue(value);
        };
    
        // TODO: I don't know how to destroy this
        return () => {
          counter.onupdate = () => {};
        };
      }, [value]);
    
      // When the tickValue is updated, update the Tick.DOM element
      useEffect(() => {
        if (tickRef.current) {
          tickRef.current.value = tickValue;
        }
      }, [tickValue]);
    
      return (
        <div ref={divRef} className="tick">
          <div data-repeat="true">
            <span data-view="flip">Tick</span>
          </div>
        </div>
      );
    };