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>
2
Answers
You have an issue with your map function:
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:
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.
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:
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 forpopStatus
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 userid
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 insidesetState
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.js
Screenshot of how user info is displayed in sequence no matter what order users are clicked: