英文:
How to properly display div content when click users randomly in React
问题
以下是代码部分的翻译:
<!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>
希望这对你有所帮助。如果你有其他问题,可以随时问我。
英文:
The code below successfully display users div messages at the bottom of the page when clicked Users button serially (Eg User1, User2, user3 etc.)
Here is my issue: when I click the Users Button randomly (Eg. User1, user6, user5, user12 etc.) The div message box gets scattered all over the page as can be seen in the screenshot below.
I do not know if the issue is from CSS or React components.
How do I get each of the user's message div to be displayed correctly at the bottom whether the users button is clicked serially or randomly?
<!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>
答案1
得分: 1
你的问题部分是由于你的CSS和JSX中的条件渲染逻辑导致的。
CSS
你有一个样式化的包装器,无论popStatus
是否为true,都会显示给每个用户。这个样式化的包装器具有固定宽度,因此无论内部是否实际渲染任何内容,都会占用页面上的空间。
更具体地说,你为每个用户渲染了这个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
styles.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 },
// ...(其他用户)
]
};
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>
);
}
用户信息按顺序显示的屏幕截图,无论用户点击的顺序如何:
英文:
Your issue is partly the result of your CSS and partly the result of your conditional rendering logic in your JSX.
CSS
You have a styled wrapper that displays for every user regardless of whether popStatus
is true. That styled wrapper has a fixed width so it takes up space on the page whether or not anything actually renders inside of it.
More specifically, you’re rendering this div for every user:
<div key={i} className="contact_box" >
Take a look at where this line sits in your JSX.
The column gaps you see between user info boxes are these div
being rendered. You can use whatever CSS you want just keep in mind if you include an element wrapping your conditional check for popStatus
in your render then it will show for each user.
The most straightforward solution is to just remove it or move it down inside the render after your conditional check.
Conditional Rendering
When you map over users you can perform your conditional check for popStatus
first.
This way, you will only render something when the condition is met.
Also better to set the key
to be the user id
to uniquely identify the user rather than use an index.
NOTE: You should avoid mutating state directly. This line: this.state.arr[id].popStatus = true;
should be moved inside setState
and you should return a new copy when performing this update.
NOTE: It's unclear what the popStatus
prop on the top level object in your state is doing as it seems irrelevant to your problem. I commented it out from the demo.
The demo below should get you going in the right direction I think.
Example/Demo (View at the link below)
https://codesandbox.io/s/user-list-pop-example-vuyx59
styles.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>
);
}
Screenshot of how user info is displayed in sequence no matter what order users are clicked:
答案2
得分: 0
你的地图功能存在问题:
{this.state.arr.map((obj, i) => (
<div key={i} className="contact_box">
{obj.popStatus === true && (
<div className="">
<b>Username:</b> {obj.name}<br />
// 剩余的内容
</div>
}
</div>
)}
首先,你先打印了contact_box
div,然后再检查popStatus
,基于它来打印内容。因为你为contact_box
设置了CSS,它总是被打印出来,所以会出现空白区域。
只需将contact_box
div 移到 if 语句内部,问题就应该解决了:
{this.state.arr.map((obj, i) => (
{obj.popStatus === true &&
<div key={i} className="contact_box">
<b>Username:</b> {obj.name}<br />
// 剩余的内容
</div>
}
)}
在这个过程中,你可以摆脱这个额外的 div。
此外,我建议使用函数组件和钩子(hooks),这将更容易管理状态,也是较新版本的React推荐的做法。
英文:
You have an issue with your map function:
{this.state.arr.map((obj, i) => (
<div key={i} className="contact_box" >
{obj.popStatus === true && <div className="">
<b>Username:</b> {obj.name}<br />
First you print contact_box div, and later you check popStatus, and based on that you print content. Because you set CSS for the cotact_box, which is printed always, you have these blank spots.
Just move contact_box div inside if statement, and it should be fine:
{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>
}
)}
In the process, you can rid of this additional div.
Also, I recommend using functional component and hooks, it will be simpler to manage the state, and it is recommended for newer React versions.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论