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

react hooks 如何实现父组件调用子组件的方法?

  •  1
     
  •   xiaoming1992 · 2020-06-03 00:13:48 +08:00 · 5902 次点击
    这是一个创建于 1394 天前的主题,其中的信息可能已经有所发展或是发生改变。

    两点前提:

    1. 函数式组件, 使用 react hooks
    2. 子组件导出方法, 供父组件在恰当的时机(想什么时候就什么时候)调用

    我唯一想到的方法是使用 ref, 如下, 但是这也太 TM 丑了, 求助大佬们

    type ChildFunc = () => number
    
    // eslint-disable-next-line react/display-name
    const Child = React.forwardRef((props, ref) => {
    
      // eslint-disable-next-line no-param-reassign
      (ref as React.MutableRefObject<ChildFunc | undefined>).current = () => 5
    
      return <>I am child</>
    })
    
    // Parent
    function Parent() {
      const funcRef = useRef<ChildFunc>()
    
      const theRightTime = new Promise((resolve) => {
        setTimeout(resolve, 1000)
      })
    
      useEffect(() => {
        theRightTime.then(() => {
          if (funcRef.current) {
            console.log(funcRef.current())
          }
        })
      }, [funcRef, theRightTime])
    
      return <Child ref={funcRef} />
    }
    

    顺便提一嘴, react 官网顶部有个"条幅" -- "黑人的命也是命。 支持公正司法倡议。" -- 但是各位可以切换语言看一下, 好像只有简体中文和英文有, 繁体中文、日文等都没有(那么多语言, 我也没一个一个翻, 但是我看了的好几个都没有)

    第 1 条附言  ·  2020-06-03 08:50:05 +08:00
    讲一下问题的起因吧,我正在做一个翻纸牌的小游戏。
    有一大批纸牌,**我认为**每张纸牌应该有一定的的智慧和自主权决定自己是正面还是反面,从原则上来讲,我不想干涉它。我的做法是当子组件切换状态的时候通知父组件。

    可是从业务上讲,我又需要有能力(vip 功能),控制每一张牌的翻面。

    有朋友提到单向数据流,确实,如果直接由父组件指定每个子组件的状态,那这个问题根本就不是问题,可是因为是自己的玩具,所以我想任性一把(可是实力不允许😂)
    17 条回复    2020-11-26 05:22:39 +08:00
    fuermosi777
        1
    fuermosi777  
       2020-06-03 01:13:15 +08:00
    要不子组件还是 class 吧
    crs0910
        2
    crs0910  
       2020-06-03 03:31:04 +08:00 via iPhone
    为什么不把 theRightTime 作为 context 给子组件用呢
    crs0910
        3
    crs0910  
       2020-06-03 03:34:34 +08:00 via iPhone
    这个运动的声明好像是 Django rest api 的作者发起的,他们是直接把官方文档给换成了支持声明。react 只挂个横幅也算是很大支持了。
    ps4512
        4
    ps4512  
       2020-06-03 05:34:54 +08:00 via iPhone
    callback
    dartabe
        5
    dartabe  
       2020-06-03 05:48:00 +08:00
    react 不是应该单项数据流吗 你这个要求是不是应该把 function 直接放到父组件或者 util ?

    我是菜鸟哈
    WittBulter
        6
    WittBulter  
       2020-06-03 06:40:20 +08:00   ❤️ 1
    React 有一个 useImperativeHandle 允许你用 hooks 的方式向外部暴露指定的实例属性或方法。

    给你写了一个在线示例可以参考: https://codesandbox.io/s/invoker-child-methdos-gtwch?file=/src/app.js
    ChefIsAwesome
        7
    ChefIsAwesome  
       2020-06-03 08:28:52 +08:00
    传 ref 本质上就是传了个 onLoad 函数给子组件。子组件 mount 之后调这个函数,并且把它自己传进去。
    你这个子组件提供方法的问题是一个道理。
    xiaoming1992
        8
    xiaoming1992  
    OP
       2020-06-03 09:27:26 +08:00
    @fuermosi777 我其他功能和样式都写完了,不想改了啊 T.T
    @crs0910 这个 theRightTime 只是表明,在恰当的时机,由父组件触发而已,本质上还是说父组件需要在恰当的时机调用子组件的方法啊
    @ps4512 跟 callback 应该没什么关系吧
    @dartabe 确实放到父组件就没有这些问题了,只是有些私心,可以看看我 append 的内容
    @WittBulter 这个 hook 我倒是确实不知道,涨姿势了,感谢(但是说实话,这样还是不够"优雅"啊...)
    @ChefIsAwesome 不管是 ref 也好,全局变量也好,目前来看虽然勉强能实现,但是都有些丑,6L 的应该算是目前最佳的了
    xiaoming1992
        9
    xiaoming1992  
    OP
       2020-06-03 09:30:02 +08:00
    @WittBulter 不对,仔细看了一下,应该还是比较优雅的,比较完美贴合我这个需求的
    hantsy
        10
    hantsy  
       2020-06-03 15:37:59 +08:00
    BlackLivesmatter 现在闹得比疫情还严重,不光是美国,欧洲也开始打杂抢了。
    KuroNekoFan
        11
    KuroNekoFan  
       2020-06-04 12:30:39 +08:00
    方法很多比如
    父组件改子组件的 props 然后子组件把这个 props 作为 dependency 来触发行为
    LeoooY
        12
    LeoooY  
       2020-06-04 13:04:42 +08:00
    我一般是把子组件封装成一个 useXXX(),然后 return dom 和需要调用的方法
    const useChild=()=>{
    return {
    }
    }
    LeoooY
        13
    LeoooY  
       2020-06-04 13:05:38 +08:00   ❤️ 1
    我一般是把子组件封装成一个 useXXX(),然后 return dom 和需要调用的方法
    const useChild=()=>{
    return {
    dom: <child />
    methods:{}
    }
    }
    xiaoming1992
        14
    xiaoming1992  
    OP
       2020-06-04 15:06:28 +08:00 via Android
    @LeoooY 这倒是一个好方法,我当时怎么没想到呢。。。我已经把原来由子组件控制的属性大部分移到父组件了。。。
    xiaoming1992
        15
    xiaoming1992  
    OP
       2020-06-04 15:09:34 +08:00 via Android
    @KuroNekoFan 可能不太行吧?之所以说希望子组件暴露出函数,就是因为函数用起来方便且语义明晰,用属性可能在这两方面不太合适吧?
    KuroNekoFan
        16
    KuroNekoFan  
       2020-06-04 17:31:23 +08:00
    @xiaoming1992 所谓'子组件暴露出函数',react 是不希望开发者这样做的
    https://zh-hans.reactjs.org/docs/hooks-reference.html#useimperativehandle 官方文档也说了,应当避免
    除了我说的用 props 控制,还可以用事件,状态管理之类的
    gamesover
        17
    gamesover  
       2020-11-26 05:22:39 +08:00
    我有类似的 user case
    假设有一个 list 的 input checkbox,value 是从 1 到 10
    这些 checkbox 本身是可以自由 check 或者 uncheck 的

    但是我又希望提供一个范围比如 3 和 6,然后用户点击一个选择按钮,选中范围在 3 到 6 之间的 checkbox

    这两种选中方式互不影响,如何优雅的实现这一点呢?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2576 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 15:55 · PVG 23:55 · LAX 08:55 · JFK 11:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.