pqina / flip

⏳ The online version of the classic flip clock
https://pqina.nl/flip/
MIT License
893 stars 87 forks source link

Flip not working with transform in combination with React #9

Closed deadcoder0904 closed 4 years ago

deadcoder0904 commented 4 years ago

The 1st example on https://pqina.nl/flip/ (Event Countdown) is not working when I add transform

I get the following error:

TypeError: value.map is not a function

Without it, it works perfectly fine.

Here's a codesandbox demo: https://codesandbox.io/s/flip-transform-not-working-bqmwg?file=/src/EventCountdown.js

Here's the code for brevity:

App.js

import React from "react";
import "./styles.css";
import { EventCountdown } from "./EventCountdown";

export default function App() {
  return (
    <div className="App">
      <h1>Flip not working with transform</h1>
      <EventCountdown value="2021" />
    </div>
  );
}

EventCountdown.js

import React, { useRef, useEffect, useState } from "react";
import Tick from "@pqina/flip";

export const EventCountdown = ({ 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: ["y", "M", "d", "h", "m", "s"]
    });

    // When the counter updates, update React's state value
    counter.onupdate = function(value) {
      setTickValue(value);
    };

    return () => {
      counter.timer.stop();
    };
  }, [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"
        data-layout="horizontal fit"
        data-transform="preset(d, h, m, s) -> delay"
      >
        <div className="tick-group">
          <div
            data-key="value"
            data-repeat="true"
            data-transform="pad(00) -> split -> delay"
          >
            <span data-view="flip" />
          </div>

          <span data-key="label" data-view="text" className="tick-label" />
        </div>
      </div>
    </div>
  );
};

Working examples with React can be found here: https://codesandbox.io/s/react-flip-countdown-timer-8tin3?file=/src/App.js

deadcoder0904 commented 4 years ago

No worries just got it working. Weird spent 2 days trying to figure it out & after I posted got the answer 🤦‍♂️

Here's the codesandbox: https://codesandbox.io/s/flip-transform-not-working-bqmwg?file=/src/EventCountdown.js

Posting code for brevity:

App.js

import React from "react";
import "@pqina/flip/dist/flip.min.css";
import { EventCountdown } from "./EventCountdown";

export default function App() {
  return (
    <div>
      <h1>Flip not working with transform</h1>
      <h1>
        <EventCountdown value="2021-01-01T00:00:00+01:00" />
      </h1>
    </div>
  );
}

EventCountdown.js

import React, { useRef, useEffect, useState } from "react";
import Tick from "@pqina/flip";

export const EventCountdown = ({ 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);
    };

    return () => {
      counter.timer.stop();
    };
  }, [value]);

  // When the tickValue is updated, update the Tick.DOM element
  useEffect(() => {
    if (tickRef.current) {
      tickRef.current.value = tickValue;
    }
  }, [tickValue]);

  return (
    <div className="tick">
      <div
        data-repeat="true"
        data-layout="horizontal fit"
        data-transform="preset(d, h, m, s) -> delay"
      >
        <div className="tick-group">
          <div
            ref={divRef}
            data-repeat="true"
            data-transform="pad(00) -> split -> delay"
          >
            <span data-view="flip" />
          </div>

          <span data-key="label" data-view="text" className="tick-label" />
        </div>
      </div>
    </div>
  );
};

Just 1 tiny little problem. It fills the whole screen up with 10 characters (the time in ISO format) on the 1st reload.

Anyway to suppress that? I'll try myself to see if there's a way.

deadcoder0904 commented 4 years ago

Another minor issue is single digit number is written as 7 instead of 07 even though in transform, there is a pad(00). Maybe the , is shown instead of 0?

Would love to know an answer to that as well?

Same codesandbox demonstrating what I am talking about: https://codesandbox.io/s/flip-transform-not-working-bqmwg?file=/src/EventCountdown.js

deadcoder0904 commented 4 years ago

I'll open another issue to better keep track of it :)

Opened #10, #11 & #12 👍

dritter commented 3 years ago

I might be late to the party, but I found the error: The problem arises from setting an initial Value. If you remove that, it should work as expected. Change this:

Tick.DOM.create(currDiv, {
      value,
      didInit
    });

Into this:

Tick.DOM.create(currDiv, {
      didInit
    });

Disclaimer: I did not try it out in React, but I had the same Problem when creating a Svelte wrapper. I had similar code, and changing it, worked.

Edit: I was referring to TypeError: value.map is not a function. Dont know, if this fixes the other errors as well..