skip to Main Content

The code below successfully display users div messages at the bottom of the page when clicked Users button serially (Eg User1, User2, user3 etc.)

Screenshot_Serial

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?

screenshot_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


  1. 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.

    Login or Signup to reply.
  2. 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:

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search