bvaughn / react-virtualized-auto-sizer

Standalone version of the AutoSizer component from react-virtualized
MIT License
613 stars 82 forks source link

Access the component height from outside the component to pass to itemSize #86

Closed rchancey closed 8 months ago

rchancey commented 8 months ago

Hi ya @bvaughn , I am using the react-window and the react-virtualized auto sizer.. and I have a virtual book that I display and each paragraph is a component.

the paragraphs are variable heights.. of course that changes based on the width of the page etc etc.

using the ref I can get the height and set that within the function.. or even use react -use-measure... but the challenge exposing that height outside the component to use that to get set the height in the auto-sizer itemSize

Any ideas on how to export a components height outside the component so I can pass it to the autosized? Hope this makes sense.

might even be interesting to make this a built in thing that the auto0sizer can work with flex components

bvaughn commented 8 months ago

This sounds like a question about react-window, rather than a question about this library. The AutoSizer component passes the dimensions of the outer container (the thing your list is rendered into). The variable size of an item in the list is managed by the list itself (react-window)

If you want variable height support, I might suggest you check out react-virtualized as it has built-in support for this.

rchancey commented 8 months ago

Tried it.. hit the same issue as others. renders the first set of elements and stops. Also it still wants a row height.

I can't figure out how to give any of the react-window or react-virtualized a list that has random heights and not have to set a row height..thats the piece thats missing. Is there a simple example of that we can look at? its a GREAT library and it renders my 500k list easily. . just need the final piece not to have to pass a row height @bvaughn ?

rchancey commented 8 months ago

It seems others have done what I ended up doing and using a ref to get the rendered height of the list row and use that in the getrowHeight: https://github.com/bvaughn/react-window/issues/582

I thought there was a way to automate that somehow.. @bvaughn great library btw.. we owe you a coffee for sure man !

bvaughn commented 8 months ago

I can't figure out how to give any of the react-window or react-virtualized a list that has random heights

That's what the CellMeasurer component is intended to be used for (see the docs) but it sounds like you got it figured out.

@bvaughn great library btw.. we owe you a coffee for sure man !

Thank you! he he he givebrian.coffee

bvaughn commented 8 months ago

P.S. Thanks so much for your generosity 🙇🏼

rchancey commented 8 months ago

Hey @bvaughn ...well that code did not work since React 18 does not like it. The height is zero.

I will look at the CellMeasurer might have the right idea.. set a default value and then adjust as it render... I noticed in the examples there was some flickering and line redraws.. so .. not sure. React 18 does not like rendering invisible somehow.. it did not generate a height. .. I will update. you but if you have any other ideas.. would be greatly appreciated.

this is a very common use case it seems.... just have to get the right combination! :)

rchancey commented 8 months ago

@bvaughn most welcome... you have done a great job.. and actually I am combining your libraries, with react highlight (also your library) and lunr .. sort of interesting :)

rchancey commented 8 months ago

@bvaughn do you do contract work? Are you interested if you are not yet?

bvaughn commented 8 months ago

Thank you! I really appreciate OSS interactions like this one. :)

Dynamic height is a tough use case to get right. That's why I didn't really try to support it with react-window.

I don't know if this would even be remotely useful to you, but I remember putting together a really minimal example project a few years ago that was just vanilla JS (no React) that showed how you could do a dynamically sized virtual list: https://github.com/bvaughn/infinite-list-reflow-examples

@bvaughn do you do contract work? Are you interested if you are not yet?

I haven't done contract work in a long time. I probably don't have the bandwidth for it, unless it would be a very small project.

rchancey commented 8 months ago

@bvaughn What's the right way to contact you outside this git so I can share our project to see if you are interested. It would be very small for your skills but still challenging enough to make it interesting. Very simple use case. We are using 3... in fact I think 4 of your libraries :) . I did not realize they were all yours until last night on a call with someone. haha.

bvaughn commented 8 months ago

That's a funny coincidence :)

Email is the best way to contact me. brian.david.vaughn@gmail.com

rchancey commented 8 months ago

@bvaughn I did follow one of the examples .. but there are no scroll bars.. but it is doing a decent job rendering..

here is the code in case others are looking for this same thing. but why no scroll bars? in fact the scrolling is a little jerky.

// Mo// Modules
import React, { useEffect, useRef } from "react";
// Components
import { VariableSizeList as List } from "react-window";
import AutoSizer from "react-virtualized-auto-sizer";
// Styles
import styles from "./Regulations.css";

const RegulationList = ({ documents }) => {
    // References
    const listRef = useRef({});
    const rowHeights = useRef({});

    function getRowHeight(index) {
        return rowHeights.current[index] || 40;
    }

    function Row({ index, style }) {
        const rowRef = useRef({});

        useEffect(() => {
            if (rowRef.current) {
                setRowHeight(index, rowRef.current.clientHeight);
            }
            // eslint-disable-next-line
        }, [rowRef]);

        return (
            <div style={style}>
                <div ref={rowRef} style={styles.documentContainer}>
                    {documents[index]}
                </div>
            </div>
        );
    }

    function setRowHeight(index, size) {
        listRef.current.resetAfterIndex(0);
        rowHeights.current = { ...rowHeights.current, [index]: size };
    }

    return (
        <AutoSizer style={styles.listContainer}>
            {({ height, width }) => (
                <List
                    className="List"
                    height={height}
                    itemCount={documents.length}
                    itemSize={getRowHeight}
                    ref={listRef}
                    width={width}
                >
                    {Row}
                </List>
            )}
        </AutoSizer>
    );
};

export default RegulationList;

const styles = {
    listContainer: {
      height: "700px",
      width: "100%"
    },
    documentContainer: {
      display: "flex",
      flex: "0 0 auto",
      justifyContent: "flex-start",
      width: "100%"
    }
  };

  export default styles;

Edited for formatting by @bvaughn

bvaughn commented 8 months ago

This looks wrong:

function setRowHeight(index, size) {
  listRef.current.resetAfterIndex(0);
  rowHeights.current = { ...rowHeights.current, [index]: size };
}

Try:

function setRowHeight(index, size) {
  rowHeights.current = { ...rowHeights.current, [index]: size };
  listRef.current.resetAfterIndex(index);
}

That being said, this thread has gone pretty far off track for this repo, so it's probably best to wind it down. :)