如何在React中点击随机用户时正确显示div内容

huangapple go评论62阅读模式
英文:

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

如何在React中点击随机用户时正确显示div内容

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?

如何在React中点击随机用户时正确显示div内容

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;script src=&quot;build/react.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;build/react-dom.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;build/browser.min.js&quot;&gt;&lt;/script&gt;
&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;
&lt;style&gt;
.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; 
}
&lt;/style&gt;
&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/babel&quot;&gt;
class Application extends React.Component {
constructor(props) {
super(props);
this.state = {
arr: [
{ id: 1,     name: &quot;user1&quot;},
{ id: 2,     name: &quot;user2&quot;},
{ id: 3,     name: &quot;user3&quot;},
{ id: 4,     name: &quot;user4&quot;},
{ id: 5,     name: &quot;user5&quot;},
{ id: 6,     name: &quot;user6&quot;},
{ id: 7,     name: &quot;user7&quot;},
{ id: 8,     name: &quot;user8&quot;},
{ id: 9,     name: &quot;user9&quot;},
{ id: 10,    name: &quot;user10&quot;},
{ id: 11,    name: &quot;user11&quot;},
{ id: 12,    name: &quot;user12&quot;},
{ id: 13,    name: &quot;user13&quot;},
{ id: 14,    name: &quot;user14&quot;},
{ id: 15,    name: &quot;user15&quot;}
],
popStatus: false,
};
this.popIt = this.popIt.bind(this);
}
popIt(id) {
this.state.arr[id].popStatus = true;
this.setState({
popStatus: true
});
}
render() {
return (
&lt;div&gt;
&lt;h3&gt;List of users Records&lt;/h3&gt;
&lt;div class=&quot;sidebar&quot;&gt;
&lt;ul&gt;
{this.state.arr.map((obj, i) =&gt; (
&lt;li key={i}&gt;
{obj.name} - {obj.name}
&lt;button
type=&quot;button&quot;
onClick={() =&gt; { this.popIt(i); }}
className=&quot;&quot;
&gt;
{obj.name}
&lt;/button&gt;
&lt;/li&gt;
))}
&lt;/ul&gt;
&lt;/div&gt;
&lt;div className=&quot;mainArea&quot;&gt;
{this.state.arr.map((obj, i) =&gt; (
&lt;div  key={i} className=&quot;contact_box&quot; &gt;
{obj.popStatus === true &amp;&amp; &lt;div className=&quot;&quot;&gt;
&lt;b&gt;Username:&lt;/b&gt; {obj.name}&lt;br /&gt;
Message .........&lt;br /&gt;
Message .........&lt;br /&gt;
Message .........&lt;br /&gt;
Message .........&lt;br /&gt;
Message .........&lt;br /&gt;
Message .........&lt;br /&gt;
&lt;/div&gt; 
} 
&lt;/div&gt; 
))}
&lt;/div&gt;
&lt;/div&gt;
);
}
}
ReactDOM.render(&lt;Application /&gt;, document.getElementById(&#39;app&#39;));
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

答案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>
  );
}

用户信息按顺序显示的屏幕截图,无论用户点击的顺序如何:

如何在React中点击随机用户时正确显示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:

&lt;div  key={i} className=&quot;contact_box&quot; &gt;

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.

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 &quot;./styles.css&quot;;
import { useState } from &quot;react&quot;;
const initialState = {
users: [
{ id: 1, name: &quot;user1&quot;, popStatus: false },
{ id: 2, name: &quot;user2&quot;, popStatus: false },
{ id: 3, name: &quot;user3&quot;, popStatus: false },
{ id: 4, name: &quot;user4&quot;, popStatus: false },
{ id: 5, name: &quot;user5&quot;, popStatus: false },
{ id: 6, name: &quot;user6&quot;, popStatus: false },
{ id: 7, name: &quot;user7&quot;, popStatus: false },
{ id: 8, name: &quot;user8&quot;, popStatus: false },
{ id: 9, name: &quot;user9&quot;, popStatus: false },
{ id: 10, name: &quot;user10&quot;, popStatus: false },
{ id: 11, name: &quot;user11&quot;, popStatus: false },
{ id: 12, name: &quot;user12&quot;, popStatus: false },
{ id: 13, name: &quot;user13&quot;, popStatus: false },
{ id: 14, name: &quot;user14&quot;, popStatus: false },
{ id: 15, name: &quot;user15&quot;, popStatus: false }
]
// what was this for?
// popStatus: false
};
export default function App() {
const [state, setState] = useState(initialState);
function popIt(id) {
setState((prev) =&gt; {
return {
...prev,
users: prev.users.map((user) =&gt;
user.id === id ? { ...user, popStatus: true } : user
)
};
});
}
return (
&lt;div className=&quot;App&quot;&gt;
&lt;h3&gt;List of users Records&lt;/h3&gt;
&lt;ul style={{ listStyle: &quot;none&quot; }}&gt;
{state.users.map((user) =&gt; (
&lt;li key={user.id}&gt;
{user.name}{&quot; &quot;}
&lt;button
type=&quot;button&quot;
onClick={() =&gt; {
popIt(user.id);
}}
&gt;
{user.name}
&lt;/button&gt;
&lt;/li&gt;
))}
&lt;/ul&gt;
&lt;div className=&quot;main-area&quot;&gt;
{state.users.map(
(user) =&gt;
user.popStatus &amp;&amp; (
&lt;div key={user.id} className=&quot;contact-box&quot;&gt;
&lt;b&gt;Username:&lt;/b&gt;
{user.name}
&lt;br /&gt;
Message .........
&lt;br /&gt;
Message .........
&lt;/div&gt;
)
)}
&lt;/div&gt;
&lt;/div&gt;
);
}

Screenshot of how user info is displayed in sequence no matter what order users are clicked:

如何在React中点击随机用户时正确显示div内容

答案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) =&gt; (
&lt;div  key={i} className=&quot;contact_box&quot; &gt;
{obj.popStatus === true &amp;&amp; &lt;div className=&quot;&quot;&gt;
&lt;b&gt;Username:&lt;/b&gt; {obj.name}&lt;br /&gt;

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) =&gt; (
{obj.popStatus === true &amp;&amp;
&lt;div  key={i} className=&quot;contact_box&quot; &gt;
&lt;b&gt;Username:&lt;/b&gt; {obj.name}&lt;br /&gt;
// rest of the box
&lt;/div&gt;
}
)}

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.

huangapple
  • 本文由 发表于 2023年2月16日 05:41:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/75465705.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定