React Virtualized: коллекция с ячейками, которые имеют одинаковую фиксированную высоту, но разную ширину

Я немного смущен, могу ли я использовать компонент React Virtualized Collection для решения моей проблемы. Попробую описать то, что делаю:

Я использую React Virtualized на странице для отображения двух списков / коллекций элементов. Я закончил первую коллекцию, в которой есть элементы одинаковой ширины и высоты:

Коллекция, в которой ячейки имеют одинаковую высоту и ширину

Первая коллекция была довольно простой и простой в реализации. Сейчас я работаю над второй коллекцией, которая содержит изображения разных размеров. Я хочу, чтобы ячейки имели одинаковую высоту, но разную ширину (конечно, в зависимости от размеров изображения). Проблема в том, что в строках не всегда может быть одинаковое количество ячеек:

Коллекция, в которой ячейки имеют одинаковую высоту, но разную ширину

Возможно ли этого достичь с помощью React Virtualized? Если да, как я могу определить позицию в cellSizeAndPositionGetter?


person Jooooooooohn    schedule 12.01.2017    source источник
comment
Короткий ответ: нельзя. Обходной путь, о котором я могу думать, - это разделение всех ячеек на фактические строки, поэтому в строке 1 будут первые три изображения, а в строке 2 будут следующие четыре в вашем случае. Затем вы виртуализируете сами строки, а не отдельные ячейки. Это конструктивное ограничение виртуализированных списков в целом (список, а не сетка).   -  person Sergiu Paraschiv    schedule 12.01.2017
comment
Я согласен с тем, что сказал Серджиу. Чтобы добавить еще немного, лучшая коллекция, которую вы показали, действительно должна быть Grid, а не Component. Grid более эффективен и прост в использовании. Второй, который вы показываете, может быть List, но вычислить количество строк будет немного сложно.   -  person bvaughn    schedule 12.01.2017
comment
@brianvaughn Полагаю, вы имеете в виду Collection, а не Component? В любом случае, я понимаю, что вы оба говорите. Думаю, попробую Grid для первой коллекции. Для второй коллекции я использовал CassetteRocks / react-infinite-scroller. Когда у меня появится свободное время, я снова попробую реализовать вторую коллекцию с помощью React Virtualized. Потому что репо мне очень нравится! :) Спасибо вам обоим за ваш вклад.   -  person Jooooooooohn    schedule 13.01.2017
comment
Извини да. Напечатано неправильно. :) Рад слышать!   -  person bvaughn    schedule 13.01.2017


Ответы (1)


Недавно я использовал react-virtualized List для отображения строк карточек изображений с фиксированной высотой и переменной шириной, и это отлично сработало.

Мой List rowRenderer использует массив строк элементов изображения карты. То есть массив массивов реагирующих компонентов, как JSX.

См. Мою последнюю функцию cardsRows, чтобы узнать, как я строю строки на основе ширины элементов и ширины экрана.

Вот как это выглядит:

Макет строк списка

Надеюсь это поможет!

Некоторые фрагменты моего кода:

import {AutoSizer, List} from 'react-virtualized';

...

updateDimensions() {
    this.setState({
        screenWidth: window.innerWidth,
    });
}

componentDidMount() {
    window.addEventListener("resize", this.updateDimensions);
}


componentDidUpdate(prevProps, prevState) {
    const props = this.props;
    const state = this.state;

    if (JSON.stringify(props.imageDocs) !== JSON.stringify(prevProps.imageDocs) || state.screenWidth !== prevState.screenWidth)
        this.setState({
            cardsRows: cardsRows(props, state.screenWidth),
        });
}


rowRenderer({key, index, style, isScrolling}) {
    if (!this.state.cardsRows.length)
        return '';
    return (
        <div id={index} title={this.state.cardsRows[index].length} key={key} style={style}>
            {this.state.cardsRows[index]}
        </div>
    );
}

...

render() {
    return (
            <div style={styles.subMain}>
                <AutoSizer>
                    {({height, width}) => (<List height={height}
                                                 rowCount={this.state.cardsRows.length}
                                                 rowHeight={164}
                                                 rowRenderer={this.rowRenderer}
                                                 width={width}
                                                 overscanRowCount={2}
                        />
                    )}
                </AutoSizer>
            </div>
    );
}

...

const cardsRows = (props, screenWidth) => {

    const rows = [];
    let rowCards = [];
    let rowWidth = 0;
    const distanceBetweenCards = 15;

    for (const imageDoc of props.imageDocs) {
        const imageWidth = getWidth(imageDoc);

        if (rowWidth + distanceBetweenCards * 2 + imageWidth <= screenWidth) {
            rowCards.push(cardElement(imageDoc));
            rowWidth += distanceBetweenCards + imageWidth;
        }
        else {
            rows.push(rowCards);
            rowCards = [];
            rowWidth = distanceBetweenCards;
        }
    }
    if (rowCards.length) {
        rows.push(rowCards);
    }
    return rows;
};


const styles = {
    subMain: {
        position: 'absolute',
        display: 'block',
        top: 0,
        right: 0,
        left: 0,
        bottom: 0,
    }
};
person stuart    schedule 22.01.2017
comment
Немного устарело, но как вы обрабатывали события изменения размера окна? - person Patrick; 03.07.2018