Как правильно отображать содержимое div при случайном нажатии пользователей в ответ

Приведенный ниже код успешно отображает сообщения пользователей div внизу страницы при последовательном нажатии кнопки «Пользователи» (например, «Пользователь1», «Пользователь2», «Пользователь3» и т. д.).

Вот моя проблема: когда я случайно нажимаю кнопку «Пользователи» (например, User1, user6, user5, user12 и т. д.), окно сообщения Div разбрасывается по всей странице, как видно на снимке экрана ниже.

Я не знаю, связана ли проблема с css или с реактивными компонентами.

Пожалуйста, как мне заставить каждое из сообщений пользователя DIV отображаться правильно внизу, независимо от того, нажимается ли кнопка пользователя последовательно или случайным образом

<!DOCTYPE html>
<html>
   <head>

   </head>
   <body>
<script src = "build/react.min.js"></script>
<script src = "build/react-dom.min.js"></script>
<script src = "build/browser.min.js"></script>
<meta name = "viewport" content = "width=device-width, initial-scale=1">

<style>
.mainArea {
  position: fixed;
  width: 80%;
  bottom: 0%
}
.contact_box {
  position: relative;
  bottom: -5px;
  width: 250px;
  background: black;
  color: red;
  border-radius: 5px 5px 0px 0px;
  bottom: 0px;
  display: inline-block; 
}
</style>
<div id = "app"></div>
<script type = "text/babel">

class Application extends React.Component {
  constructor(props) {
    super(props);
this.state = {
      arr: [
    { id: 1,     name: "user1"},
    { id: 2,     name: "user2"},
    { id: 3,     name: "user3"},
    { id: 4,     name: "user4"},
    { id: 5,     name: "user5"},
    { id: 6,     name: "user6"},
    { id: 7,     name: "user7"},
    { id: 8,     name: "user8"},
    { id: 9,     name: "user9"},
    { id: 10,    name: "user10"},
    { id: 11,    name: "user11"},
    { id: 12,    name: "user12"},
    { id: 13,    name: "user13"},
    { id: 14,    name: "user14"},
    { id: 15,    name: "user15"}
      ],
popStatus: false,

    };
   this.popIt = this.popIt.bind(this);
  }

  popIt(id) {
   
this.state.arr[id].popStatus = true;
this.setState({
          popStatus: true
        });
     }

  render() {
    return (
        <div>
          <h3>List of users Records</h3>
<div class = "sidebar">
          <ul>
            {this.state.arr.map((obj, i) => (
              <li key = {i}>
                {obj.name} - {obj.name}
 <button
                  type = "button"
                  onClick = {() => { this.popIt(i); }}
                  className = ""
                >
                 {obj.name}
                </button>
              </li>
            ))}
          </ul>
      </div>
<div className = "mainArea">
            {this.state.arr.map((obj, i) => (
              <div  key = {i} className = "contact_box" >
{obj.popStatus === true && <div className = "">
        <b>Username:</b> {obj.name}<br />
          Message .........<br />
          Message .........<br />
          Message .........<br />
          Message .........<br />
          Message .........<br />
          Message .........<br />
</div> 
   } 
</div> 
 ))}
</div>
</div>
    );
  }
}
ReactDOM.render(<Application />, document.getElementById('app'));
</script>
   </body>
</html>

Вы хотите использовать другое значение для свойства ключа. Индекс не является надежным значением для ключа. Моя любимая статья о том, почему: kentcdodds.com/blog/understanding-reacts-key-prop

esinator 15.02.2023 22:44

@esinator, если я использую obj.id в качестве ключевого реквизита, он не работает, поэтому проблема сохраняется. Пожалуйста, у вас все еще есть какое-либо другое решение

Nancy Moore 15.02.2023 23:07

Дайте мне знать, полезен ли мой обновленный пример в ответе ниже. Я думаю, может быть, вы можете немного объяснить, что вы надеетесь сделать с popIt и popStatus, но, надеюсь, пример поможет.

abgregs 16.02.2023 00:04

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

abgregs 16.02.2023 05:34
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
4
54
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

У вас проблема с функцией карты:

{this.state.arr.map((obj, i) => (
    <div  key = {i} className = "contact_box" >
        {obj.popStatus === true && <div className = "">
           <b>Username:</b> {obj.name}<br />

Сначала вы печатаете div contact_box, а позже проверяете popStatus и на основе этого печатаете содержимое. Поскольку вы устанавливаете CSS для cotact_box, который всегда печатается, у вас есть эти белые пятна.

Просто переместите div contact_box внутрь оператора if, и все должно быть в порядке:

{this.state.arr.map((obj, i) => (
   {obj.popStatus === true &&
       <div  key = {i} className = "contact_box" >
           <b>Username:</b> {obj.name}<br />
           // rest of the box
       </div>
   }
 )}

В процессе можно избавиться от этого дополнительного div.

Также рекомендую использовать функциональный компонент и хуки, так будет проще управлять состоянием, и это рекомендуется для более новых версий React.

Ответ принят как подходящий

Ваша проблема частично является результатом вашего CSS и частично результатом вашей логики условного рендеринга в вашем JSX.

CSS

У вас есть стилизованная оболочка, которая отображается для каждого пользователя независимо от того, истинно ли popStatus. Эта стилизованная оболочка имеет фиксированную ширину, поэтому она занимает место на странице независимо от того, что внутри нее действительно отображается.

Точнее, вы визуализируете этот div для каждого пользователя:

<div  key = {i} className = "contact_box" >

Посмотрите, где эта строка находится в вашем JSX.

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

Самое простое решение — просто удалить его или переместить вниз внутри рендера после условной проверки.

Условный рендеринг

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

Таким образом, вы будете отображать что-то только тогда, когда условие будет выполнено.

Также лучше установить key как пользователя id, чтобы однозначно идентифицировать пользователя, а не использовать индекс.

ПРИМЕЧАНИЕ. Следует избегать прямого изменения состояния. Эта строка: this.state.arr[id].popStatus = true; должна быть перемещена внутрь setState, и вы должны вернуть новую копию при выполнении этого обновления.

ПРИМЕЧАНИЕ. Неясно, что делает опора popStatus на объекте верхнего уровня в вашем состоянии, поскольку это кажется неуместным для вашей проблемы. Я прокомментировал это из демо.

Я думаю, что приведенная ниже демонстрация должна направить вас в правильном направлении.

Пример/демонстрация (см. ссылку ниже)

https://codesandbox.io/s/user-list-pop-example-vuyx59

стили.css

.App {
  font-family: sans-serif;
  text-align: center;
}

.main-area {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
}

.contact-box {
  background: black;
  color: red;
  border-radius: 5px 5px 0px 0px;
  padding: 10px;
}

App.js

import "./styles.css";
import { useState } from "react";

const initialState = {
  users: [
    { id: 1, name: "user1", popStatus: false },
    { id: 2, name: "user2", popStatus: false },
    { id: 3, name: "user3", popStatus: false },
    { id: 4, name: "user4", popStatus: false },
    { id: 5, name: "user5", popStatus: false },
    { id: 6, name: "user6", popStatus: false },
    { id: 7, name: "user7", popStatus: false },
    { id: 8, name: "user8", popStatus: false },
    { id: 9, name: "user9", popStatus: false },
    { id: 10, name: "user10", popStatus: false },
    { id: 11, name: "user11", popStatus: false },
    { id: 12, name: "user12", popStatus: false },
    { id: 13, name: "user13", popStatus: false },
    { id: 14, name: "user14", popStatus: false },
    { id: 15, name: "user15", popStatus: false }
  ]
  // what was this for?
  // popStatus: false
};

export default function App() {
  const [state, setState] = useState(initialState);

  function popIt(id) {
    setState((prev) => {
      return {
        ...prev,
        users: prev.users.map((user) =>
          user.id === id ? { ...user, popStatus: true } : user
        )
      };
    });
  }
  return (
    <div className = "App">
      <h3>List of users Records</h3>
      <ul style = {{ listStyle: "none" }}>
        {state.users.map((user) => (
          <li key = {user.id}>
            {user.name}{" "}
            <button
              type = "button"
              onClick = {() => {
                popIt(user.id);
              }}
            >
              {user.name}
            </button>
          </li>
        ))}
      </ul>
      <div className = "main-area">
        {state.users.map(
          (user) =>
            user.popStatus && (
              <div key = {user.id} className = "contact-box">
                <b>Username:</b>
                {user.name}
                <br />
                Message .........
                <br />
                Message .........
              </div>
            )
        )}
      </div>
    </div>
  );
}

Снимок экрана, показывающий, как информация о пользователе отображается последовательно, независимо от того, в каком порядке нажимаются пользователи:

Другие вопросы по теме