如何给一个函数组件挂载 ref 上去? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yazoox
V2EX    React

如何给一个函数组件挂载 ref 上去?

  •  
  •   yazoox 2022 年 1 月 28 日 2502 次点击
    这是一个创建于 1443 天前的主题,其中的信息可能已经有所发展是发生改变。

    最新在使用 react-dnd ,如下例子,useDrag 会返回一个 drag ,这个需要挂载到一个组件的 ref 上去 如果是一个 html element 或者 class component ,是有 ref 的,但是一个函数组件,是没有 ref 的,怎么挂上去呢?

    export const Box = function Box({ name }) { const [{ isDragging }, drag] = useDrag(() => ({ type: ItemTypes.BOX, item: { name }, end: (item, monitor) => { const dropResult = monitor.getDropResult(); if (item && dropResult) { window.alert(`You dropped ${item.name} into ${dropResult.name}!`); } }, collect: mOnitor=> ({ isDragging: monitor.isDragging(), handlerId: monitor.getHandlerId() }) })); const opacity = isDragging ? 0.4 : 1; return ( <div ref={drag} style={{ ...styleBox, opacity }} data-testid={`box-${name}`} > {name} </div> ); }; 

    如果是个函数组件,比如,div 换成一个 function component ,drag 无法生效。 debug into react-dnd 的源代码,就会发现,找不到 drag source,因为 ref 一直是 null

    export const Box = function Box({ name }) { const [{ isDragging }, drag] = useDrag(() => ({ type: ItemTypes.BOX, item: { name }, end: (item, monitor) => { const dropResult = monitor.getDropResult(); if (item && dropResult) { window.alert(`You dropped ${item.name} into ${dropResult.name}!`); } }, collect: mOnitor=> ({ isDragging: monitor.isDragging(), handlerId: monitor.getHandlerId() }) })); const opacity = isDragging ? 0.4 : 1; return ( <FunctionComponent ref={drag} style={{ ...styleBox, opacity }} data-testid={`box-${name}`} > {name} </FunctionComponent> ); }; 

    当然,这个 FunctionComponent 也是一个复杂组件,可能级联下去,孙子的孙子也是一个 div 元素。 但是怎么能够把 react-dnd 的的这个 drag ,传递给孙子的孙子的 div 元素 ref 元素呢?

    谢谢!

    11 条回复    2022-02-11 17:34:02 +08:00
    GentleFifth
        1
    GentleFifth  
       2022 年 1 月 28 日 via Android
    forwardRef
    momocraft
        2
    momocraft  
       2022 年 1 月 28 日
    这个 ref 应该设计目的是给 DOM element 的 (得到一个 class component 的 instance 没意义, 因为不知道把 event handler 挂到 DOM 的哪里去)

    因此不管是 class comopnent 还是 FC, 你都可以通过一个不叫 ref 的 prop 传递 只要最终传到一个 DOM element 就行
    yazoox
        3
    yazoox  
    OP
       2022 年 1 月 28 日
    @momocraft 但这个 FC 是第三方的组件,不是我们自己的。这个就得去改他们的源代码了。可能比较难。

    @GentleFifth 能多说两句么?
    Yukee798
        4
    Yukee798  
       2022 年 1 月 28 日
    React.forwardRef 应该能解决你的问题,可以去看一下文档 https://react.docschina.org/docs/forwarding-refs.html
    GentleFifth
        5
    GentleFifth  
       2022 年 1 月 28 日 via Android
    @yazoox 2 楼是对的,如果 FC 是第三方组件的话,建议外面包一层 div ,给 react-dnd 使用,forwardRef 可以给 FC 透传 ref
    momocraft
        6
    momocraft  
       2022 年 1 月 28 日
    如果这个 FC 无法以任何方式塞自己的 DOM element 进去 (包括 children 和各种 props) , 就套一层 div 好了
    shilianmlxg
        7
    shilianmlxg  
       2022 年 1 月 28 日
    听大佬们分析 学了好多东西
    66beta
        8
    66beta  
       2022 年 1 月 28 日
    你这组件没有 forwardRef 吧
    yazoox
        9
    yazoox  
    OP
       2022 年 2 月 11 日
    @momocraft 谢谢。
    “通过一个不叫 ref 的 prop 传递" 是可以的,我已经尝试过了,可以工作。
    再请教一下,
    如果一个 FC ,层级下去,都是 FC ,只到最后一层才是一个 DOM Element 、HTML element ,那是不是每一层的 FC ,都需要使用 forwardRef 包装一下,把 ref 赋值给下一层的 ref prop ?


    @66beta 没有。但这个组件有 N 层,只在第一层 forwardRef ,不够吧?是不是得每层都 forwardRef 一下?
    66beta
        10
    66beta  
       2022 年 2 月 11 日
    @yazoox 可以 props 一层层传下去,为什么要在外层操作遥远的里层?
    KuroNekoFan
        11
    KuroNekoFan  
       2022 年 2 月 11 日
    一层一层传感觉好痛苦,这种我选择 context....
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1015 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 23:23 PVG 07:23 LAX 15:23 JFK 18:23
    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