Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ResizeObserver not being triggered when content height changes (React)

It works when I manually resize the window, but not when the content height changes which is what I need.

Am I doing something wrong?

class MainContainer extends React.Component {
  constructor(props) {
    super(props);
    this.containerRef = React.createRef();
    this.containerObserver = null;
    this.state = {
      top: false,
    };
  }

  componentDidMount() {
    this.containerObserver = new ResizeObserver((e) => this.handleResize(e));
    this.containerObserver.observe(this.containerRef.current);
  }

  componentWillUnmount() {
    if (this.containerObserver) {
      this.containerObserver.disconnect();
    }
  }

  handleResize = (e) => {
    const { target } = e[0];

    const top = target.scrollTop;
    const scrollHeight = target.scrollHeight;
    const position = scrollHeight - top;
    const clientHeight = target.clientHeight;

    console.log({ top }, { scrollHeight }, { position }, { clientHeight });

    if (top < 10) {
      if (this.state.top) {
        this.setState({ top: false });
      }
    } else {
      if (!this.state.top) {
        this.setState({ top: true });
      }
    }

    if (position >= clientHeight - 40 && position <= clientHeight) {
      if (!this.state.top) {
        this.setState({ top: true });
      }
    }
  };

  render() {
    return (
      <React.Fragment>
        <Container ref={this.containerRef} onScroll={this.handleScroll}>
          <Body />
        </Container>
        <ShadowTop show={this.state.top} />
      </React.Fragment>
    );
  }
}

--

export const Container = styled.div`
  @media (max-width: 760px) {
    position: absolute;
  }

  margin-top: ${({ theme }) => theme.header.height.percent}%;
  margin-top: -webkit-calc(${({ theme }) => theme.header.height.pixel}px);
  margin-top: -moz-calc(${({ theme }) => theme.header.height.pixel}px);
  margin-top: calc(${({ theme }) => theme.header.height.pixel}px);

  height: ${({ theme }) => Math.abs(100 - theme.header.height.percent)}%;
  height: -webkit-calc(100% - ${({ theme }) => theme.header.height.pixel}px);
  height: -moz-calc(100% - ${({ theme }) => theme.header.height.pixel}px);
  height: calc(100% - ${({ theme }) => theme.header.height.pixel}px);

  position: fixed;
  float: none;
  clear: both;
  top: 0;
  right: 0;

  width: ${({ theme }) => 100 - theme.sidebar.width.percent}%;
  width: -webkit-calc(100% - ${({ theme }) => theme.sidebar.width.pixel}px);
  width: -moz-calc(100% - ${({ theme }) => theme.sidebar.width.pixel}px);
  width: calc(100% - ${({ theme }) => theme.sidebar.width.pixel}px);


  z-index: 2;
  pointer-events: auto;
  overflow: auto;
`;
like image 426
Nikk Avatar asked Apr 07 '26 11:04

Nikk


2 Answers

You are observing Container for size change, but it has fixed dimensions:

 height: ${({ theme }) => Math.abs(100 - theme.header.height.percent)}%;
 // ... 

 width: ${({ theme }) => 100 - theme.sidebar.width.percent}%;

so it never actually resizes, and resize observer never triggers.

Try wrapping its content inside an element that shrinks to the size of its content, and use the resize observer on this element instead:

this.contentObserver.observe(this.contentRef.current);

// ...
<Container onScroll={this.handleScroll}>
   <ShrinkWrapper ref={this.contentRef}>
      <Body />
   </ShrinkWrapper>
</Container>
const ShrinkWrapper = styled.div`
   width: fit-content;
   height: fit-content;
`
like image 103
Michal Kurz Avatar answered Apr 10 '26 01:04

Michal Kurz


Solved it by using a MutationObserver with subtree enabled.

this.containerObserver = new MutationObserver(this.handleResize);
this.containerObserver.observe(this.containerRef.current, {
    childList: true,
    subtree: true,
});
like image 44
Nikk Avatar answered Apr 10 '26 01:04

Nikk



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!