ResizeObserver alternatives and fallback in Next.js

241 Views Asked by At

ResizeObserver is not supported by Safarai on a bit older versions (I think youger than 2018/2019) so I am looking for a fallback that can be set in case ResizeObserver is undefined.

For some reason in Next.js/React onResize event doesn't fire at all.

The component is quite simple by itself:

import React, { PropsWithChildren, useCallback, useEffect, useRef, useState } from 'react'
import clsx from 'clsx'
import { ChevronDownIcon } from '../Icons/Icons'

import './ConfigSection.scss'

interface IConfigSectionProps extends PropsWithChildren {
    title: string
    icon: React.ReactNode
    spacing?: 'normal' | 'large'
}

export const ConfigSection: React.FC<IConfigSectionProps> = ({
    title,
    icon,
    children,
    spacing = 'normal'
}) => {
    const contentRef = useRef<HTMLDivElement>(null)

    const [ contentHeight, setContentHeight ] = useState(0)
    const [ isSectionOpen, setIsSectionOpen ] = useState(true)

    const handleToggleSectionOpen = useCallback(() => {
        setIsSectionOpen(isSectionOpen => !isSectionOpen)
    }, [])

    useEffect(() => {
        if(!ResizeObserver) {
            return
        }

        const contentElement = contentRef.current as Element
        const resizeObserver = new ResizeObserver(([configSection]) => {
            setContentHeight(configSection.target.clientHeight)
        })

        resizeObserver.observe(contentElement)

        return () => {
            resizeObserver.disconnect()
        }
    }, [setContentHeight])

    return (
        <div
            className={clsx('config-section', {
                "config-section_open": isSectionOpen
            })}
        >   
            <div
                className='config-section__header'
                onClick={handleToggleSectionOpen}
            >
                <div className='config-section__title'>
                    {icon} {title}
                </div>

                <ChevronDownIcon />
            </div>

            <div
                style={{
                    transition: 'all 0.3s ease',
                    overflow: 'hidden',
                    height: isSectionOpen ? `${contentHeight || contentRef.current?.clientHeight}px` : '0px'
                }}
            >
                <div
                    ref={contentRef}

                    // NOTE: Doesn't fire event
                    onResize={...}

                    className={clsx('config-section__content', {
                        'config-section__content_large-spacing': spacing === 'large'
                    })}
                >
                    {children}
                </div>
            </div>
        </div>
    )
}

The resize will fail if there is no ResizeObserver and the component will break, using contentRef to add addEventListener is bad practice in React as far as I know, someone correct me if I'm wrong.

Thanks in advance :)

0

There are 0 best solutions below