想要实现 点击每个项的设置,展示对应的设置框。
设置框的展示与否设置了通过show
属性来判断
<div className={i.show ? 'menu-show' : 'menu-hide'}>
<p>名称: {i.name}</p>
<p>年龄: <input type="text"/></p>
</div>
点击 box 框时 也设置了 <div key={i.name} className="box" onClick={() => i.show = !i.show}>
可为什么没效果呢? 下面是 demo 代码。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<style>
* {
padding: 0;
margin: 0;
}
.wrapper, h1 {
display: flex;
margin: auto 220px;
}
.box {
font-size: 16px;
background-color: #00a0e9;
margin: 3px;
border-radius: 3px;
padding: 3px;
}
.menu-hide, .menu-show {
margin-top: 12px;
}
.menu-hide {
display: none;
}
.menu-show {
display: block;
}
</style>
</head>
<body>
<div id="root"></div>
</body>
<script type="text/babel">
const App = () => {
const [items, setItems] = React.useState([{name: 'twitch', age: 3}, {name: '虎牙', age: 5}, {name: '斗鱼', age: 6}])
return <div>
<h1>study</h1>
<div className="wrapper">
{items.map(i => {
i.show = false
return <div key={i.name} className="box" onClick={() => i.show = !i.show}>
<p>名称 {i.name}</p>
<p>年龄: {i.age}</p>
<a href="#">设置</a>
<div className={i.show ? 'menu-show' : 'menu-hide'}>
<p>名称: {i.name}</p>
<p>年龄: <input type="text"/></p>
</div>
</div>
})}
</div>
</div>
}
ReactDOM.createRoot(document.getElementById('root')).render(<App/>)
</script>
</html>
1
darkengine 2022-08-26 19:48:12 +08:00
先搞清楚最基本的 state 概念,setItems 都没调用怎么会有变化呢。
|
2
morri OP 我试过 有调用 ` setItems(items[index].show = true)` 这样也不行。
@darkengine <div className="wrapper"> {items.map((i, index) => { i.show = false return <div key={i.name} className="box" onClick={() => { setItems(items[index].show = true) }}> <p>名称 {i.name}</p> <p>年龄: {i.age}</p> <a href="#">设置</a> <div className={i.show ? 'menu-show' : 'menu-hide'}> <p>名称: {i.name}</p> <p>年龄: <input type="text"/></p> </div> </div> })} </div> 但是 在 telegram 群里面问的哥哥 这样改下就可以了 在遍历里面 再使用 ` const [show, setShow] = React.useState(false);` ``` <div className="wrapper"> {items.map(i => { const [show, setShow] = React.useState(false); return <div key={i.name} className="box" onClick={() => setShow(v => !v)}> <p>名称 {i.name}</p> <p>年龄: {i.age}</p> <a href="#">设置</a> <div className={show ? 'menu-show' : 'menu-hide'}> <p>名称: {i.name}</p> <p>年龄: <input type="text"/></p> </div> </div> })} </div> ``` 好奇为什么要这样用才行。 |
3
GentleFifth 2022-08-26 20:23:18 +08:00 via Android
之前是不是写 vue 的
|
4
GPLer 2022-08-26 20:36:13 +08:00 1
1. React 在更新的时候只会对 State 进行**浅比较**,对于数组对象这样的引用类型,光修改内部值,React 无法知道其发生变化,这个 Vue2 其实也是这样的,要解决这个问题,最简单的办法就是 setItems(items.slice()) 创建一个新的数组并赋值,让 React 知道发生了变化.
2. 你一开始的代码,像 i.show = false 这样的初始化语句不能写在这,return 的 JSX 可以视作渲染函数,每次都会被调用,相当于每次都会执行,意味着 show 一直都为 false ,这个如果真的不方便直接写在数组里,可以用 React.useEffect 套一下。 3. 为什么你后面发的代码再写一个 State 可以解决,因为这个 State 内的数据类型是简单的数据类型,直接变化是 React 可以检测到的,所以 React 会重新渲染,但这样只解决了更新的问题,你的目的是取反,这样做只能让值变 true ,不能变 false ,因为页面更新后值又变成了 false 。 4. 所以基于你修改后的版本,建议将 ``` const [show, setShow] = React.useState(false); ``` 改为 ``` const [show, setShow] = React.useState(i.show || false); ``` 并将 ``` onClick={() => setShow(v => !v)} ``` 改为 ``` onClick={() => { i.show = !i.show;setShow(i.show); }} ``` 5. 本人是写 Vue 的,以上的回复不保证其正确性( |
5
darkengine 2022-08-26 20:42:17 +08:00
肯定不行,要整个 Object 都换掉
items[index].show = true setItems([...items]) |
6
morri OP |
7
morri OP @darkengine 多谢回答,这样也不行 还是要在遍历的里面使用 const [show, setShow] = React.useState(false) 才行
|
8
okakuyang 2022-08-26 21:19:50 +08:00
如果你用一个数组存储列表各行是否显示的状态 ,你在设置显隐的时候要传一个新的数组进去。
例如: displayList[index] = true setDiseplayList( Array.from( displayList ) ) 数组里面是对象也是一样,你都需要传递一个新数组进去。 |