Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a property of initially undefined variable for useEffect dependency

TL;DR: Want to use listRef.current.clientWidth for useEffect dependency.

I wanted to make a list where it automatically resizes its item's widths according to list's width. I'm so close but I can't detect the change of listRef.current.clientWidth which is <div className="dynamic-list">'s width. At the first run listRef is null, so I can't have listRef.current.clientWidth for the useEffect dependency. listRef ? listRef.current.clientWidth : null for the dependency also doesn't work with use simple dependency warning.

const DynamicList = ({
  dataSource, renderItem, itemMaxWidth, itemHeight,
  margin, height = 500, width = 700 }) => {
  const windowWidth = useWindowDimensions().width; 
  const [itemStyle, setItemStyle] = useState({ width: itemMaxWidth, height: itemHeight });
  const [currentWidth, setCurrentWidth] = useState(null);
  const listRef = useRef();


  useEffect(() => {
    if (listRef) {
      const num = Math.floor(listRef.current.clientWidth / itemMaxWidth)
      console.log(
        num,
        listRef.current.clientWidth,
        listRef.current
      )
      setItemStyle((pre) => ({
        ...pre,
        height: itemHeight,
        margin: margin,
        width: (listRef.current.clientWidth / num) - (margin ? margin * 2 : 0),
      }))
    }

  }, [listRef, windowWidth, itemMaxWidth, margin, itemHeight, width])

  return (
    <div
      className="dynamic-list"
      ref={listRef}
      style={{
        width: width,
        height: height
      }}
    >
      {
        dataSource.map((item, index) => {
          return (
            <div style={itemStyle} key={index}>
              {renderItem(item, index)}
            </div>
          )
        })
      }
    </div>
  );
};

export default DynamicList;
  • Any tips on making this better would be really appreciated.
like image 309
Inyoung Kim 김인영 Avatar asked Oct 17 '25 04:10

Inyoung Kim 김인영


1 Answers

Using callback ref like @TopW3 said, I was able to solve the problem. Not fully satisfied though. Article that also helped me solve the problem

const DynamicList = ({
  dataSource, renderItem, itemMaxWidth, itemHeight,
  margin, height = 500, width = 700 }) => {
  const windowWidth = useWindowDimensions().width; // 윈도우 크기 변화 감지용
  const [itemStyle, setItemStyle] = useState({
    width: itemMaxWidth,
    height: itemHeight,
    margin: margin
  });
  const [listWidth, setListWidth] = useState(null);

  const onListRefSet = useCallback((ref) => {
    if (ref)
      if (ref.current)
        setListWidth(ref.current.clientWidth);
  })

  useEffect(() => {
    if (listWidth) {
      const num = Math.floor(listWidth / itemMaxWidth);
      setItemStyle((pre) => ({
        ...pre,
        width: (listWidth / num) - (margin ? margin * 2 : 0),
      }))
    }
  }, [listWidth, itemMaxWidth, margin, itemHeight, windowWidth])

  return (
    <div
      className="dynamic-list"
      ref={onListRefSet}
      style={{
        width: width,
        height: height,
        minWidth: itemMaxWidth
      }}
    >
      {
        dataSource.map((item, index) => {
          return (
            <div style={itemStyle} key={index}>
              {renderItem(item, index)}
            </div>
          )
        })
      }
    </div>
  );
};

export default DynamicList;
like image 183
Inyoung Kim 김인영 Avatar answered Oct 19 '25 20:10

Inyoung Kim 김인영



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!