ollie
ollie

Reputation: 823

Get heights of child components in React

I need to access the heights of child components in React but can't find any clear guidance on how best to do it. My Component looks like this:

/* index.js */
import Blocks from './Blocks'

ReactDOM.render(<Blocks />, document.body)

/* Blocks.jsx */
import Block from './Block'

class Blocks extends Component {
  render () {
    const eles = [0, 1, 2, 3, 4]

    return (
      <div>
        {eles.map(e => <Block key={e}>{e}</Block>)}
      </div>
    )
  }
}

I want to know the size and position of each of those Blocks as I want to position them myself later.

As far as I can see, this approach doesn't allow me to use this.props.children to access the elements which is annoying as rendering the blocks in this way is much better for me (there's going to be logic around which type of Block to render later). To get around this I've tried moving the rendering of the Blocks into the index file like this:

/* index.js */
import Blocks from './Blocks'
import Block from './Block'

const eles = [0, 1, 2, 3, 4]

ReactDOM.render(
  <Blocks>
    {eles.map(e => <Block key={e}>{e}</Block>)}
  </Blocks>
)

/* Blocks.jsx */
class Blocks extends Component {
  render () {
    return (
      <div>
        {this.props.children}
      </div>
    )
  }
}

What this allows me to do is use refs inside the individual Block components to return the result of their getBoundingClientRect function which I should be able to access through the parent but I'm now reading that using refs is discouraged and not how React is supposed to be used.

I need to be able to pin certain Blocks to the top of the screen as they are scrolled past and can't think of any other way of doing it than knowing their sizes and positions in a parent component and using that to manage them. Is there any way of doing this? Ideally I would like to move that loop back inside of the Blocks component otherwise I'm going to have some of it's logic in an unrelated component which doesn't seem right.

I've also looked into using react-sticky but as the app I'm building is already inside a fixed position element (which is unavoidable) I don't think it'll help me.

Upvotes: 1

Views: 8993

Answers (1)

Pei Han
Pei Han

Reputation: 156

try to use callback function in Block Component to send the ref to the Parent Component

Block.js

import React, { Component } from 'react';

class Block extends Component {
  componentDidMount() {
    this.props.getRef(this.block, this.props.i);
  }
  render() {
    return (
      <div ref={n => this.block = n}>
        <p>{this.props.children}</p>
      </div>
    );
  }
}

export default Block;

save the refs into variable or state in index.js, and then in componentDidMount method, you can get the Block component height or other property. index.js

const eles = [0, 1, 2, 3, 4];

class App extends Component {
  constructor() {
    super();
    this.blocks = [];
  }


  componentDidMount() {
    console.log(this.blocks);
    this.blocks.forEach((block, i) => {
      console.log(i, block.getBoundingClientRect().height)
    })
  }

  getRef = (ref, i) => {
    this.blocks[i] = ref;
  };

  render() {
    return (
      <div>
        {eles.map((e, i) => (
          <Block key={e} i={i} getRef={this.getRef}>{e}</Block>
        ))}
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));

the result in console enter image description here

Upvotes: 8

Related Questions