search

Home  >  Q&A  >  body text

Append to top of div in React without messing with scroll state

I'm having trouble with react. I'm trying to implement a simple scrollable div that contains a lot of child divs that can be viewed with horizontal scrolling.

Basically each child div corresponds to a day. This component loads the first time a user views information about the current day and the following days. However, if the user scrolls (left or right), I would like to be able to append more information, implementing some kind of "infinite scroll functionality".

When I try to append a new child div at the end of the parent div, I don't have any problems. However, when I try to append a new child element at the beginning of the parent div (e.g. the user wants to see content from previous days), the scroll changes after adding the new element, causing the user to be confused as to why the scroll is changing .

I created a small JS fiddle to replicate my setup. Try clicking "Add Left" and you will see the current behavior. Is there a way to add new elements without changing the entire view? https://jsfiddle.net/k75pvey3/3/

P.s. I saw a lot of answers to this question online. However, all of these I've seen assume that the new component has a specific width. In my case (as I'm trying to show in the fiddle), I can't determine the width of the newly added child div.

Here is the code for reference:

function App(props) {

  const [array, setArray] = React.useState(['100', '321', '32', '412', '12', '33', '54'])

  const addLeft = () => {
    setArray([Math.floor(Math.random()*300), ...array])
  }
  
  const addRight = () => {
    setArray([...array, Math.floor(Math.random()*300)])
  }

  return (
    <div className='App'>
      <button onClick={addLeft}>add left</button>
      <button onClick={addRight}>add right</button>
      <div className="container">
        {array.map(i => (<div className="element" style={{minWidth:i}}>{i}</div>))}
      </div>
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector("#app"))

This is the CSS:

.container {
  background-color: red;
  width: 550px;
  height: 120px;
  margin: auto;
  display: flex;
  overflow: auto;
}

.element {
  height: 100px;
  background-color: yellow;
  margin: 10px;
  font-size: 30px;
  color: black;
  display: flex;
}

P粉217629009P粉217629009282 days ago486

reply all(1)I'll reply

  • P粉953231781

    P粉9532317812024-03-20 09:56:17

    I have bad news for you, this is usually one of the complicated parts of virtual lists - adding a new element at the beginning of the scroll axis while maintaining the scroll position.

    It is usually recommended that you use an existing solution such as react-virtualized or react-window.

    If you don't want to use an existing library, one solution is that you can listen to the width of the content inside the div (eg. Element.scrollWidth), and then set the value of the .scrollLeft container. However, things get complicated when you load while scrolling, as scrolling can be "with inertia", especially on touchscreen devices/touchpads on laptops.

    (As a rule of thumb, when I'm overconfident I can write a dummy list myself and end up using the library due to a lot of edge cases)

    reply
    0
  • Cancelreply