Приведенный ниже код успешно отображает сообщения пользователей 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>
@esinator, если я использую obj.id в качестве ключевого реквизита, он не работает, поэтому проблема сохраняется. Пожалуйста, у вас все еще есть какое-либо другое решение
Дайте мне знать, полезен ли мой обновленный пример в ответе ниже. Я думаю, может быть, вы можете немного объяснить, что вы надеетесь сделать с popIt
и popStatus
, но, надеюсь, пример поможет.
Причина, по которой проблема не устранена, описана в ответах ниже.
У вас проблема с функцией карты:
{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.
У вас есть стилизованная оболочка, которая отображается для каждого пользователя независимо от того, истинно ли 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>
);
}
Снимок экрана, показывающий, как информация о пользователе отображается последовательно, независимо от того, в каком порядке нажимаются пользователи:
Вы хотите использовать другое значение для свойства ключа. Индекс не является надежным значением для ключа. Моя любимая статья о том, почему: kentcdodds.com/blog/understanding-reacts-key-prop