Search code examples
javascriptreactjsnext.jsreact-virtualized

How to notify List component that its row item height has changed and make the row rerenders?


I have a react-virtualized List, each item in the rows have an expand button, when the button is clicked the height of the row changes and it expands and show more info.

the issue here is, after the button got clicked the inner Grid (ReactVirtualized__Grid__innerScrollContainer) CSS height property is not updating or the Gid is not re-rendering/notified of the changes in row height

What should I do to make it rerender the row everytime the row item height gets updated?

here is my main index.js file:

import React, {
  cloneElement,
  Component,
  useMemo,
  useCallback,
  useEffect,
  createRef,
  useRef,
  useState
} from "react";

import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";
import {
  List,
  AutoSizer,
  CellMeasurer,
  CellMeasurerCache
} from "react-virtualized";

import Expander from "./expander.js";

export default function Test() {
  // List data as an array of strings
  let list = [
    "Brian Vaughn",
    "Bob Smith",
    "Someone Else",
    "I hate making up names"
    // And so on...
  ];

  const listRef = useRef();

  const expander = (
    <Expander onChanged={() => listRef.current?.list?.forceUpdateGrid()} />
  );

  return (
    <div>
      <AutoSizer
      // disableWidth
      // disableHeight
      >
        {({ width, height }) => {
          return (
            <List
              ref={listRef}
              className="List"
              autoHeight
              width={800}
              height={400}
              rowCount={list.length}
              rowHeight={30}
              rowRenderer={({ index, isScrolling, key, style }) => (
                <div className="Row" key={key} style={style}>
                  {list[index]}
                  {expander}
                </div>
              )}
            />
          );
        }}
      </AutoSizer>
    </div>
  );
}

Here is my expander.js file ( Row Component ):

import React, {
  cloneElement,
  Component,
  useMemo,
  useCallback,
  useEffect,
  createRef,
  useRef,
  useState
} from "react";
import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";

export default function Expander(props) {
  // State : Declare
  const [isClicked, setIsClicked] = useState(false);

  const renderMoreText = () => {
    if (isClicked) {
      return (
        <div style={{ backgroundColor: "red", height: 200 }}>
          long lorem ipsum{" "}
        </div>
      );
    }

    return null;
  };

  useEffect(() => {
    props.onChanged();
  }, [isClicked]);

  return (
    <div>
      <button
        onClick={() => {
          setIsClicked(true);
        }}
      >
        {" "}
        Expand more text{" "}
      </button>
      {renderMoreText()}
    </div>
  );
}

Here is my sandbox: https://codesandbox.io/s/agitated-pond-xq1csq?file=/pages/index.js


Solution

  • I'm not familiar with react-virtualized, but reading the docs you could make use of the List onChanged event together with Expanders recomputeRowHeights().

    Updated sandbox (quick and dirty): https://codesandbox.io/s/charming-cookies-omi14k?file=/pages/index.js