Alex
Alex

Reputation: 21

Calculate new width on resize for a React hook

I am not sure how can I fix this so that upon screen resize a new width is set. Currently it is failing resize: TypeError: el.getBoundingClientRect is not a function It calculates the correct width on load but brakes on resize

import React, { useEffect, useCallback, useState, useLayoutEffect } from 'react'
import charts from 'charts'


const Charts = props => {
  const
    chartRenderers = {
      line: charts.d3_line(),
      horizontalBar: charts.d3_horizontal_bar(),
      tables: charts.d3_table()
    },
    // https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node
    useWidth = () => {
      const
        [width, setWidth] = useState(null),
        ref = useCallback(el => {
          console.log(el)
          if (el !== null) {
            setWidth(el.getBoundingClientRect().width);
          }
        }, []);

      useLayoutEffect(() => {
        window.addEventListener('resize', ref, false);
        return () => {
          window.removeEventListener('resize', ref);
        }
      }, [ref])

      return [width, ref];
    },
    { component, siteData } = props,
    [width, ref] = useWidth();

  useEffect(
    () => {
      const parsedData = component.type === "tables" ? JSON.parse(siteData) : siteData
      chartRenderers[component.type].renderChart(
        parsedData,
        charts.d3.select(`#${component.id}`),
        width,
        component.height,
        component.options
      )
    }
  )

  return <div id={component.id} key={component.id} ref={ref}/>
}
export default Charts

Upvotes: 1

Views: 6614

Answers (1)

Avallon Azevedo
Avallon Azevedo

Reputation: 174

It looks like you are not calling the function anywhere when the window resizes. Try changing the useWidth implementation to:

import { useState, useCallback } from 'react';

function useWidth(elementRef) {
    const [width, setWidth] = useState(null);

    const updateWidth = useCallback(() => {
        if(elementRef && elementRef.current) {
            const { width } = elementRef.current.getBoundingClientRect();
            setWidth(width);
        }
    }, [elementRef]);

    useEffect(() => {
        updateWidth();
        window.addEventListener('resize', updateWidth);
        return () => {
            window.removeEventListener('resize', updateWidth);
        }
    }, [updateWidth])

    return [width]
}

Usage

import React, { useRef } from 'react'; 

const Charts = props => {
    const ref = useRef(null);
    // rest of code

    const [width] = useWidth(ref);

    // do wherever you want with width

    return (
        <div ref={ref}/>
    )
}

Upvotes: 7

Related Questions