Дочерний компонент React заставляет элементы сетки размещаться в следующей строке горизонтально расширяемой сетки до заполнения предыдущей строки.

1
6

Потерпите, так как проблему сложно четко описать.

У меня есть приложение, которое перечисляет "элементы" в сетке. Эта сетка достаточно велика, чтобы вместить только один элемент, но она расширяется с каждым новым элементом до пяти элементов, после чего новые элементы добавляются в следующую строку. Когда вторая строка достигает пяти элементов, следующий элемент помещается в строку 3.

Изначально у меня была статическая кнопка "добавить элемент" вверху страницы, но я решил, что было бы более разумно с практической и эстетической точки зрения сделать кнопку "добавить" последним "элементом" в сетке, чтобы при нажатии кнопки "добавить" она заменялась новым элементом. Это показалось более интуитивным, поскольку кнопка "добавить" находится там, где вы добавляете другой элемент.

Я добился этого с помощью дочерних компонентов. Каждый компонент элемента сетки — это просто контейнер div, заданный с нужной шириной и высотой для заполнения одного компонента сетки, и он принимает дочерний компонент, который может быть либо элементом в сетке, либо кнопкой добавления.

Все работало нормально до использования этой схемы дочерних компонентов — и фактически все еще отлично работает с "элементами" в качестве дочерних компонентов компонентов "контейнер элементов". Однако, когда я добавляю "контейнер элементов" с кнопкой добавления в качестве дочернего компонента, эта кнопка добавления помещается в новую строку, несмотря на то, что предыдущая строка не была заполнена 5 элементами.

Красная стрелка показывает, где должна быть кнопка добавления

Что еще более странно, так это то, что когда я вставляю некоторый временный code, чтобы сделать кнопку добавления средним элементом в списке с более обычными элементами, идущими после нее, кнопка добавления появится в правильном месте в текущей строке, но все элементы после нее начнутся со следующей строки!

Элемент во 2-й строке должен быть в конце первой строки

Здесь задействовано много codeа, поэтому я надеюсь, что кто-то может иметь представление об общей проблеме в том, как кто-то может попытаться реализовать это, что приведет к такому результату. Тем не менее, я сделаю все возможное, чтобы сократить его до наиболее релевантного codeа, чтобы вы имели некоторое представление о том, что я делаю.

App.tsx:

CoinSlot.tsx:

    type AddButtonProps = {
  onAddCoinSlot: () => void;
}

type CoinsListItemProps = {
  children: React.ReactNode,
  bordered?: boolean
}

const AddButton = function (props: AddButtonProps) {
  return(
    <>
      <input type="button" onClick = {props.onAddCoinSlot} value="+" id="add-button"></input>
    </>
  )
}

const CoinsListItem = (props: CoinsListItemProps) => {
  let borderedClassName = props.bordered ? " bordered" : "";
  return(
    <div className={"coin-slot" + borderedClassName}>
      {props.children}
    </div>
  )
}
  let coinList = coinsDataWithAddButton.map((coin, index) => {
    if(coin !== null){
      return(
        <CoinsListItem bordered={true}>
          <CoinSlot 
            id={index}
            coinTicker={coin.ticker}
            addressEntryIsOpen={coin.addressEntryIsOpen}
            availableCoins={availableCoins}
            coinImage={coin.image}
            address={coin.address}
            addressIsValid={coin.addressIsValid}
            isCustom={coin.rank === -1 ? true : false}
            onChangeCoin={onChangeCoin}
            onChangeAddress={onChangeAddress}
            onChangeLogo={onChangeLogo}
            onChangeTicker={onChangeTicker}
            onRemoveCoinSlot={onRemoveCoinSlot}
            toggleAddressEntryArea={onToggleAddressEntry}
            moveCoinSlot={moveCoinSlot}
            lines={coin.lines}
          />
        </CoinsListItem>
      )
    } else {
      return (
        <CoinsListItem>
          <AddButton onAddCoinSlot={onAddCoinSlot}/>
        </CoinsListItem>
      )
    }
  })

 return (

    <div className="App">
      <div className="debug">
      </div>
      <div className="app-box">
        <h1>Cryptowidget Builder</h1>
        <div className="coin-list-container">
          <AddButton onAddCoinSlot={onAddCoinSlot}/>
          <div className="coin-list">
            {coinList}
          </div>
        </div>
        <button onClick={onGenerateQrs} value="Get widget" disabled={generationIsDisabled}>Get widget</button>
        <button onClick={makeAllAddressesValid} value="Make addresses valid (for testing)">Make Addresses Valid</button>
      </div>
    </div>
  );
    return(
    <>
        <input type="button" className="remove-button" onClick = {onRemoveCoinSlot} value="X"></input>
        <img src={props.coinImage} id="background-image" alt="coin"></img>
        <div className="coin-slot-grid">
            <div className="move-button-container">
                <button className="move-button" onClick={moveCoinSlotLeft}>{"<"}</button>
            </div>
            <div className="coin-slot-options">
                <div className="select-area">
                    <select value={props.coinTicker || ""} className = "dropdown-menu" onChange={onChangeCoin}>
                        {coinOptions}
                    </select>
                </div>

                {addressEntryElement}
                <div className={customCoinOptionsClassName}>
                    <input type="text" onChange={onChangeTicker} value={props.customTicker} className="custom-ticker-entry" placeholder="ticker"></input>
                    <input type="file" id={"logo-chooser-" + props.id.toString()} className="logo-chooser" onChange={onChangeLogo} ></input>
                </div>
            </div>
            <div className="move-button-container">
                <button className="move-button" onClick={moveCoinSlotRight}>{">"}</button>
            </div>
        </div>
    </>
)
Тит
Вопрос задан5 апреля 2024 г.

1 Ответ

2

Дочерний компонент React: Горизонтальная сетка с заполнением строк

В React вы можете создать горизонтальную сетку с заполнением строк, где дочерние компоненты размещаются в следующей строке, только когда предыдущая строка полностью заполнена. 

1. Использование CSS Grid Layout:

  • Создайте родительский элемент с display: grid:
.grid-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-gap: 10px;
}
  • Установите grid-template-columns:
    • repeat(auto-fit, minmax(200px, 1fr)) - создаст столбцы с минимальной шириной 200px и будет автоматически подстраиваться под размер контейнера.
    • grid-gap: 10px - установит пробел между элементами сетки.
  • Разместите дочерние компоненты в родительском элементе:
function MyGrid() {
  return (
    <div className="grid-container">
      {Array.from({ length: 10 }).map((_, index) => (
        <div key={index} className="grid-item">
          Item {index + 1}
        </div>
      ))}
    </div>
  );
}

2. Использование flexbox:

  • Создайте родительский элемент с display: flex и  flex-wrap: wrap:
.grid-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

.grid-item {
  width: 200px;
  margin-bottom: 10px;
}
  • Установите  width для дочерних компонентов:
    • width: 200px - установит ширину каждого дочернего элемента.
    • margin-bottom: 10px - установит отступ внизу для создания пробела между строками.
  • Разместите дочерние компоненты в родительском элементе:
function MyGrid() {
  return (
    <div className="grid-container">
      {Array.from({ length: 10 }).map((_, index) => (
        <div key={index} className="grid-item">
          Item {index + 1}
        </div>
      ))}
    </div>
  );
}

3. Использование библиотеки  react-grid-layout:

  • Установите  react-grid-layout:
npm install react-grid-layout
  • Используйте  ResponsiveGridLayout для создания сетки:
import ResponsiveGridLayout from "react-grid-layout";

function MyGrid() {
  const layout = [
    { i: "a", x: 0, y: 0, w: 1, h: 1 },
    { i: "b", x: 1, y: 0, w: 1, h: 1 },
    { i: "c", x: 2, y: 0, w: 1, h: 1 },
    { i: "d", x: 0, y: 1, w: 1, h: 1 },
    { i: "e", x: 1, y: 1, w: 1, h: 1 },
    // ...
  ];
  return (
    <ResponsiveGridLayout className="layout" layouts={layout} cols={3} rowHeight={100} width={1200}>
      {layout.map((item) => (
        <div key={item.i} style={{ width: `${item.w}00%`, height: `${item.h}00%` }}>
          Item {item.i}
        </div>
      ))}
    </ResponsiveGridLayout>
  );
}

Важно:

  • Выберите подходящий метод в зависимости от ваших нужд и сложности вашего приложения.
  • CSS Grid Layout - более гибкий и мощный метод для создания сеток.
  • Flexbox - более простой в использовании и подходит для простых сеток.
  • react-grid-layout - предоставляет более продвинутые функции, такие как перетаскивание и изменение размера элементов сетки.

 

Виктор
Ответ получен6 сентября 2024 г.

Ваш ответ

Загрузить файл.