almond-bongbong / react-slot-counter

🚀 Elevate Your UI with Dynamic, Eye-Catching Counters
https://almond-bongbong.github.io/react-slot-counter/
112 stars 12 forks source link

Re-rendering/Re-calculating on window resize? #17

Closed misstricky closed 1 year ago

misstricky commented 1 year ago

Hi! This works great, except that I have a situation where the counter's font size needs to get much smaller in mobile. Its fine on window refresh in a different window size, but without refresh, the counter doesn't look right after after window is resized back/forth from desktop to mobile. I can watch for resize in the component, and I've tried some things like:

But nothing I've tried so far to change on resize seems to work and requires window refresh for the counter to look as expected again. Is there anything I can do?

Thanks!!

almond-bongbong commented 1 year ago

Thank you for bringing up this issue, and we appreciate your detailed explanation of the challenges you're facing.

When the font size changes dynamically based on window size, re-calculating the styling becomes essential. We're considering adding a method accessible via ref that would trigger this re-calculation for situations like yours.

In the meantime, you could use two instances of the SlotMachine component, but instead of using display: none, you can use visibility: hidden to keep the component in the DOM and still allow for rendering calculations. Here's a simple example:

<SlotCounter value={123456} />
<SlotCounter containerClassName="mobile" value={123456} />

And in your CSS:

.mobile {
  visibility: hidden;
  position: fixed;
  left: -9999px;
  font-size: 12px;
}

@media screen and (max-width: 768px) {
  .mobile {
    visibility: visible;
    position: static;
  }
}

I appreciate your patience and feedback!

almond-bongbong commented 1 year ago

Another simpler approach to force re-render the component is to use a key prop. Here's an example code snippet:

const [key, setKey] = React.useState('desktop');

useEffect(() => {
  const resizeHandler = () => {
    setKey(window.innerWidth < 768 ? 'mobile' : 'desktop');
  };
  window.addEventListener('resize', resizeHandler);
  return () => window.removeEventListener('resize', resizeHandler);
}, []);

// ...

<SlotCounter key={key} ref={slot1Ref} value={123456} />

In this example, the key changes based on the window width, which triggers a re-render of the SlotCounter component. This way, the styles will be recalculated according to the new dimensions.

misstricky commented 1 year ago

Thank you for the responses! I will give these a try!

I can post a different issue, but I think I can work around this so I haven't -- one other thing I noticed is when trying to run the same tests I've always had in this component (that used to pass), I get failures having to do with I think something this might be using, /style-inject/ -- I think my project's use of styled-components might not be liking ForwardRef...

Error: Uncaught [TypeError: Cannot read property 'toString' of undefined]
        at reportException (/opt/app/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)
        at invokeEventListeners (/opt/app/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:209:9)
        at HTMLUnknownElementImpl._dispatch (/opt/app/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
        at HTMLUnknownElementImpl.dispatchEvent (/opt/app/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
        at HTMLUnknownElementImpl.dispatchEvent (/opt/app/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
        at HTMLUnknownElement.dispatchEvent (/opt/app/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
        at Object.invokeGuardedCallbackDev (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:3994:16)
        at invokeGuardedCallback (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:4056:31)
        at beginWork$1 (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:23964:7)
        at performUnitOfWork (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:22779:12) TypeError: Cannot read property 'toString' of undefined
        at /opt/app/node_modules/react-slot-counter/node_modules/style-inject/dist/style-inject.es.js:26:1
        at mountMemo (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:15846:19)
        at Object.useMemo (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:16219:16)
        at Object.useMemo (/opt/app/node_modules/react/cjs/react.development.js:1532:21)
        at /opt/app/node_modules/react-slot-counter/node_modules/style-inject/dist/style-inject.es.js:26:1
        at renderWithHooks (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:14985:18)
        at updateForwardRef (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:17044:20)
        at beginWork (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:19098:16)
        at HTMLUnknownElement.callCallback (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:3945:14)
        at invokeEventListeners (/opt/app/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:193:27)
        at HTMLUnknownElementImpl._dispatch (/opt/app/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
        at HTMLUnknownElementImpl.dispatchEvent (/opt/app/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
        at HTMLUnknownElementImpl.dispatchEvent (/opt/app/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
        at HTMLUnknownElement.dispatchEvent (/opt/app/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
        at Object.invokeGuardedCallbackDev (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:3994:16)
        at invokeGuardedCallback (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:4056:31)
        at beginWork$1 (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:23964:7)
        at performUnitOfWork (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:22779:12)
        at workLoopSync (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:22707:5)
        at renderRootSync (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:22670:7)
        at performSyncWorkOnRoot (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:22293:18)
        at scheduleUpdateOnFiber (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:21881:7)
        at updateContainer (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:25482:3)
        at /opt/app/node_modules/react-dom/cjs/react-dom.development.js:26021:7
        at unbatchedUpdates (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:22431:12)
        at legacyRenderSubtreeIntoContainer (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:26020:5)
        at Object.render (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:26103:10)
        at fn (/opt/app/node_modules/@wojtekmaj/enzyme-adapter-react-17/src/ReactSeventeenAdapter.js:458:26)
        at /opt/app/node_modules/@wojtekmaj/enzyme-adapter-react-17/src/ReactSeventeenAdapter.js:375:37
        at batchedUpdates$1 (/opt/app/node_modules/react-dom/cjs/react-dom.development.js:22380:12)
        at Object.act (/opt/app/node_modules/react-dom/cjs/react-dom-test-utils.development.js:1042:14)
        at wrapAct (/opt/app/node_modules/@wojtekmaj/enzyme-adapter-react-17/src/ReactSeventeenAdapter.js:375:13)
        at Object.render (/opt/app/node_modules/@wojtekmaj/enzyme-adapter-react-17/src/ReactSeventeenAdapter.js:444:16)
        at new ReactWrapper (/opt/app/node_modules/enzyme/src/ReactWrapper.js:115:16)
        at mount (/opt/app/node_modules/enzyme/src/mount.js:10:10)
        at Object.<anonymous> (/opt/app/static_source/js/test/campaigns/campaign-page-next/campaign-banner-test.jsx:157:19)
        at Object.asyncJestLifecycle (/opt/app/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:53:37)
        at /opt/app/node_modules/jest-jasmine2/build/queueRunner.js:43:12
        at new Promise (<anonymous>)
        at mapper (/opt/app/node_modules/jest-jasmine2/build/queueRunner.js:26:19)
        at /opt/app/node_modules/jest-jasmine2/build/queueRunner.js:73:41
        at processTicksAndRejections (internal/process/task_queues.js:95:5)

  console.error node_modules/react-dom/cjs/react-dom.development.js:20085
    The above error occurred in the <ForwardRef> component:

        at /opt/app/node_modules/react-slot-counter/node_modules/style-inject/dist/style-inject.es.js:26:1
        at div
        at div
        at campaign-banner__CampaignActionsTaken (/opt/app/node_modules/styled-components/src/models/StyledComponent.js:155:27)
        at div
        at campaign-banner__CampaignActionsTakenContainer (/opt/app/node_modules/styled-components/src/models/StyledComponent.js:155:27)
        at div
        at div
        at div
        at div
        at div
        at div
        at div
        at campaign-banner__CampaignBannerContainer (/opt/app/node_modules/styled-components/src/models/StyledComponent.js:155:27)
        at CampaignBannerNext (/opt/app/static_source/js/campaigns/campaign-page-next/campaign-banner.jsx:198:5)
        at WrapperComponent (/opt/app/node_modules/@wojtekmaj/enzyme-adapter-react-17/node_modules/enzyme-adapter-utils/src/createMountWrapper.jsx:49:26)

But I think I can get around it by mocking react-slot-counter in my tests to avoid the error. I also tried updating styled-components, but it seemed to just give me a different error, mocking is working for me though. So not asking for a fix really -- just letting you know so you're aware.

almond-bongbong commented 1 year ago

Thank you for bringing up the testing issue. Your observations are quite helpful for the ongoing development of react-slot-counter.

The conflict between styled-components and ForwardRef is something that certainly warrants further investigation. While I can't pinpoint the exact issue without more details, I'm glad to hear that mocking react-slot-counter is working as a workaround for you. I'll keep this issue in mind for future updates and improvements.

If you encounter any more issues or have additional insights, please feel free to share. Your input is highly valuable.

Thanks again for using react-slot-counter and for your constructive feedback!