React 遍历数组中的元素,渲染出来的对象如何控制子项的展示或隐藏呢? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
morri
V2EX    问与答

React 遍历数组中的元素,渲染出来的对象如何控制子项的展示或隐藏呢?

  •  
  •   morri 2022-08-26 19:13:53 +08:00 1304 次点击
    这是一个创建于 1152 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想要实现 点击每个项的设置,展示对应的设置框。

    设置框的展示与否设置了通过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> 
    8 条回复    2022-08-26 21:19:50 +08:00
    darkengine
        1
    darkengine  
       2022-08-26 19:48:12 +08:00
    先搞清楚最基本的 state 概念,setItems 都没调用怎么会有变化呢。
    morri
        2
    morri  
    OP
       2022-08-26 20:13:16 +08:00
    我试过 有调用 ` 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>

    ```
    好奇为什么要这样用才行。
    GentleFifth
        3
    GentleFifth  
       2022-08-26 20:23:18 +08:00 via Android
    之前是不是写 vue 的
    GPLer
        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 的,以上的回复不保证其正确性(
    darkengine
        5
    darkengine  
       2022-08-26 20:42:17 +08:00
    肯定不行,要整个 Object 都换掉

    items[index].show = true
    setItems([...items])
    morri
        6
    morri  
    OP
       2022-08-26 20:42:29 +08:00
    @GentleFifth 写过

    @GPLer 多谢回答!
    morri
        7
    morri  
    OP
       2022-08-26 20:50:09 +08:00
    @darkengine 多谢回答,这样也不行 还是要在遍历的里面使用 const [show, setShow] = React.useState(false) 才行
    okakuyang
        8
    okakuyang  
       2022-08-26 21:19:50 +08:00
    如果你用一个数组存储列表各行是否显示的状态 ,你在设置显隐的时候要传一个新的数组进去。
    例如:
    displayList[index] = true
    setDiseplayList( Array.from( displayList ) )
    数组里面是对象也是一样,你都需要传递一个新数组进去。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     918 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 21:15 PVG 05:15 LAX 14:15 JFK 17:15
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86