V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yazoox
V2EX  ›  React

在一个列表中,当 selected item change 了,如何合适的捕捉到这个改变?

  •  
  •   yazoox · 2021-07-01 11:43:21 +08:00 · 1337 次点击
    这是一个创建于 1002 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如图,比如,当前选中的是 "Category3 -> Layout1",因为选中了,所以有高亮背景显示,等等。

    如果此时,我选择了另外一个 Item, 比如“Category2 -> Layout2”,则,如何通知 Category3 -> Layout1 取消“选中”状态,然后 Category2 -> Layout2 则变为选中状态?

    本来我的想法是,在这个组件 /app 的全局,添加一个 selectedItem 和一个 previousSelectedItem 变量,专门用于维护”选中“状态,每次 有鼠标点击一个 Item 的时候,发送消息,改变 selected & previous selected item,再进行渲染。

    这样的话,我可能需要有一个 map, key 是 item's id, value 就是这个 item 对象。当 selected 对象改变时,通过这个 map,和 key 找到对应的 item,然后 改变它的 state,这样,react 就会只 re-render 这两个对象了,而不是 render 所有的 items.

    但感觉不是很”优雅“,所以,来请教一下大家。有没有更好的方法。

    谢谢!

    TreeView.png

    p.s.
    框架使用的是 react, redux or useReducer.

    第 1 条附言  ·  2021-07-02 17:49:26 +08:00

    我在codesandbox上面写了一个简化的版本。 大家有兴趣可以看看!

    点击一个item后,会“选中”,显示方式是后面添加了5个*号。同时de-select上一次选中的item.

    但这个方法”不好“,每次点击,都会全部re-render,一共13次。我一直希望只re-rend两次。 大家打开console看log,会有输出。

    有没有高手,指点一二,谢谢!

    https://codesandbox.io/s/treeviewdemo-geb72

    Screen Shot.png

    8 条回复    2021-07-02 14:46:30 +08:00
    alfredhot
        1
    alfredhot  
       2021-07-01 12:37:26 +08:00
    所有 Category 下的每个 Layout 都赋不同的值,
    然后将 Click(或者 selecteItem)函数提升到上一级.
    用一个 selectedItem state 来控制状态就可以.
    不知到你说的是不是这个效果.

    下面的代码撸得匆忙, 瑕疵较多, 希望不要介意.

    https://gist.github.com/alfredhot/03bdcf17ec52e847211ed3bb11fa4b40


    还有就是, 为什么是 Cagetory ...
    Leviathann
        2
    Leviathann  
       2021-07-01 13:28:58 +08:00 via iPhone
    一般是把被选中的 item 由 item list 的上层组件维护
    lybcyd
        3
    lybcyd  
       2021-07-01 13:32:00 +08:00 via Android
    如果没有特殊需求,不需要保存前一个被点击的条目吧。只需要在树状组件维护一个叫 selected 的 state,用于保存被选中 layout 的 ID 。在循环渲染中,如果该 layout 被选中,传一个 active 为 true 的 prop,用于标记高亮就可以了。当进行点击时,触发一个 change 事件,把点击的 layout ID 作为参数传递,在树状组件处修改 selected 即可。
    yazoox
        4
    yazoox  
    OP
       2021-07-01 13:47:25 +08:00
    @alfredhot

    Category 仅仅只是一个名字,测试用例,别在意。其实,都是 TreeNode
    另,兄弟,你这个方法,每次有 selected item 变化,会全部重新渲染吧。这恰恰 就是我想避免的。因为列表可能会很大......
    alfredhot
        5
    alfredhot  
       2021-07-01 13:58:24 +08:00
    @yazoox

    原来如此, 我就说应该不是这么单纯的问题!
    我有空也得自己研究研究.
    sleepwalker
        6
    sleepwalker  
       2021-07-01 23:58:40 +08:00 via iPhone
    可以考虑利用单选框,然后用:checked 选择器来施加选中样式
    siweipancc
        7
    siweipancc  
       2021-07-02 09:09:36 +08:00 via iPhone
    state 对象过大需要 react-reducer,也能做到父子依赖解藕,主要是 ui 渲染别崩了
    yazoox
        8
    yazoox  
    OP
       2021-07-02 14:46:30 +08:00
    @siweipancc 兄弟,能详细说说么?或者有没有相关文档分享一下。谢谢
    我现在也使用了 useReducer, 和 context,在 tree 的根组件处,useReducer,然后把 selectedItem 作为 props 传给子组件。
    只要任何子组件的 onClick 触发了,就会 dispatch curent item,这样根组件就拿到当前 selectedItem,然后触发 re-render,再把 selectdItem 作为 props 传下去。

    可是,这样的话,依然有上面的问题。因为组件的 props 内容变化了( props.selecteItem 变了),所以,子组件都会触发 re-render 。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2599 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 15:37 · PVG 23:37 · LAX 08:37 · JFK 11:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.