3

I have a list which contains a series of items, but I can't get it to scroll another item into view. Solutions such as this doesn't quite work, because I have to scroll up and down (basically if the list is too large, scroll it at intervals to display all items).

I made a codepen that illustrates the problem with react-scroll-to-component, but I am open to any library / native solution. The basic functionality is just scrollToComponent(ref, <options>).

The error as far as I can tell is that it attempts to scroll on the body, rather than the actual container. If you remove the height / overflow properties of the div, it will work.

Doesn't work:

<div
    style={{
    height: `200px`,
    overflow: "hidden"
    }}
>
    {this.state.items.map(item => (
    <Item ref={inst => (this[`ref_${item}`] = inst)} item={item} />
    ))}
</div>

Works:

<div>
    {this.state.items.map(item => (
    <Item ref={inst => (this[`ref_${item}`] = inst)} item={item} />
    ))}
</div>

Full code for anyone not wanting to go to codepen:

class Item extends React.Component {
  render() {
    return <div style={{ padding: `12px` }}>Item {this.props.item}</div>;
  }
}

class List extends React.Component {
  state = {
    items: [
      1,
      2,
      3,
      4,
      5,
      6,
      7,
      8,
      9,
      10,
      11,
      12,
      13,
      14,
      15,
      16,
      17,
      18,
      19,
      20
    ]
  };

  componendDidMount() {
    this.state.items.forEach(item => (this[`ref_${item}`] = React.createRef()));
  }

  onClick = () => {
    scrollToComponent(this.ref_20);
  };

  render() {
    const { items } = this.state;
    return (
      <div>
        <h1>My List</h1>
        <button onClick={this.onClick}>Clickidy</button>
        {/*Replace with <div> to see it work*/}
        <div
          style={{
            height: `200px`,
            overflow: "hidden",
            backgroundColor: "red"
          }}
        >
          {this.state.items.map(item => (
            <Item ref={inst => (this[`ref_${item}`] = inst)} item={item} />
          ))}
        </div>
      </div>
    );
  }
}
Dennis
  • 909
  • 4
  • 13
  • 30

2 Answers2

7

I'm going to give you a simple fix but this is how it works. You will need to set the overflow of the div containing all the elements to scroll. This is because if you set it to hidden all elements that are can't fit into that div get hidden. The solution I'm giving you doesn't require even using react-scroll-to-component or any package.

import React from "react";
import { render } from "react-dom";

class Item extends React.Component {
  render() {
    const { item } = this.props;
    return (
      <div style={{ padding: `12px` }} id={item}>
        Item {item}
      </div>
    );
  }
}

class List extends React.Component {
  state = {
    items: [
      1,
      2,
      3,
      4,
      5,
      6,
      7,
      8,
      9,
      10,
      11,
      12,
      13,
      14,
      15,
      16,
      17,
      18,
      19,
      20
    ]
  };


  onClick = () => {
    /** You can avoid using getElementById if you can get the div rendered by Item component using refs.
     * You can look at refs forwarding and other technics to see how you can solve this */
    const divToScrollTo = document.getElementById(`${this.ref_20.props.item}`);
    if (divToScrollTo) {
      divToScrollTo.scrollIntoView();
    }
  };

  render() {
    const { items } = this.state;
    return (
      <div>
        <h1>My List</h1>
        <button onClick={this.onClick}>Clickidy</button>
        <div
          style={{
            height: `200px`,
            overflow: "scroll",
            backgroundColor: "red"
          }}
        >
          {this.state.items.map(item => (
            <Item ref={inst => (this[`ref_${item}`] = inst)} item={item} />
          ))}
        </div>
      </div>
    );
  }
}

Or you can click the link below for the code pen solution https://codesandbox.io/s/2vo0j2w660

I haven't done more optimisations which are required in your code because I'm time bad but hope this helps

Its even easier if you used refs forwarding as shown at code pen here https://codesandbox.io/s/yjj66xl2v1 but you have to create refs in the constructor method`

Jjagwe Dennis
  • 1,643
  • 9
  • 13
  • Worked like a charm. It seemed to be the ref'ing that was actually the problem child. `overflow:scroll` is not really needed. Thanks for the help and take my upvote! – Dennis Jul 19 '18 at 07:48
  • Yeah, it's not but I assumed that maybe you needed a user to scroll over the list as well. The problem was with the way you were using and creating refs. – Jjagwe Dennis Jul 19 '18 at 08:13
1

Change line 55 from overflow: hidden to overflow: scroll.

Cesar N Mejia Leiva
  • 1,611
  • 1
  • 12
  • 18