【问题标题】:in React, Is it possible to access a class method through a ref, from an asynchronous fetch?在 React 中,是否可以通过 ref 从异步获取中访问类方法?
【发布时间】:2019-07-26 18:10:03
【问题描述】:

我有一个 react 组件(我们称之为 Uploader),它包含多种将文件上传到服务器的方法。该组件在应用程序的多个地方使用,并且有一些特殊的功能要求。我想让它的功能/方法可用于特定用例的父组件,其中我将文本发送到服务器,它存储它并返回资源的信息,包括它的 ID(上传者需要正确上传文件到资源)。基本上我希望能够将文件附加到消息中,但服务器需要一定的操作顺序。

创建资源 => 创建 fileSlot(文件元数据以 dB 为单位存储)=> 将文件上传到创建的资源 fileSlot(我需要资源 ID)

没有创建的资源,文件数据无处存放

所以我想从父组件调用 Uploader 的方法,并且我能够使其在基本级别上工作,例如按钮上的 onClick 事件。例如

const Parent = () => {

    const theRef = React.createRef()

    return (
        <div>
            <button onClick={()=>theRef.current.test()}>Test Me</button>
            <Uploader ref={theRef}
        </div>
    )
}

class Uploader extends React.Component {
    constructor(props){blabla...}

    test(){
        alert('test worked!')
    }

    render(){
        return (...blabla)
    }

}

这是一个过于简单的示例,但说明了我能够使用 Ref 调用方法的概念证明。这行得通!

但是,如果我尝试从诸如 fetch 之类的异步函数调用它,它就不再起作用了。我需要链接它,以便在创建消息后上传文件,所以看起来像这样

const Parent = () => {

    const theRef = React.createRef()

    const handleSendMessage = () => {
        fetch(params).then(json=>{
            //lets assume the response is Ok and has been converted to json()
            if(success){
                //THIS IS WHERE I WANT TO CALL THE METHOD OF THE CHILD COMPONENT WITH THE REF
                //SO IT WILL PERFORM THE FILE UPLOAD, HOWEVER IT TELLS ME THAT THE REF IS NULL

                theRef.current.test()
            }
        })
    }

    return (
        <div>
            <button onClick={handleSendMessage}>Test Me</button>
            <Uploader ref={theRef}
        </div>
    )
}

class Uploader extends React.Component {
    constructor(props){blabla...}

    test(){
        alert('test worked!')
    }

    render(){
        return (...blabla)
    }

}

所以这基本上就是我遇到的问题。我试过通过处理函数来做到这一点,所以它不是直接从“then()”中调用的,但它仍然不起作用。请记住,处理函数确实可以与 onClick 示例一起使用,但看起来它是异步的,它无法访问 ref 方法或其他东西。

有谁知道有没有办法做到这一点?

【问题讨论】:

  • const theRef = useRef() 替换const theRef = React.createRef() 有效吗?该钩子将保证您每次重新渲染时都获得相同的theRef 对象。
  • 为什么不只是传递一个更新的状态值,你可以在成功区域设置它。然后把它传给孩子。让孩子在获得更新时调用自己的方法?
  • @JohnRuddell 我想到了,问题是我还需要向它传递 resourceId 以及一些值以从组件内触发方法,并且同步传递两个道具可能会导致两次渲染,并且我宁愿不要让子组件太“量身定制”,因为我在应用程序的许多其他地方都使用它。但我正在考虑采用类似的方法作为解决方案
  • @JoshWilson 确实有效!多么美妙而简单的修复啊!我什至没有考虑过使用 ref 挂钩而不是 createRef() 函数!
  • 好吧@xunux,resourceId 可能是触发器。我会将您需要通过状态传递的内容传递给子组件,让它获得所需的道具,并在获得该道具时做它需要做的事情。就像在componentDidUpdate 中一样,您可以检查最后一个道具是否没有resourceId 或者它是否已更改:)

标签: reactjs class methods parent-child ref


【解决方案1】:

感谢@joshwilson,他的修复是最简单的修复,并且有效。通过使用 useRef 钩子而不是 createRef() 函数,现在可以按需要工作。

【讨论】:

    【解决方案2】:

    EDIT:由 Josh Wilson 评论,您需要使用 useRef 而不是 createRef,因为 ref 有可能是'没有在函数赋值的时候赋值。

    class Uploader extends React.Component {
      test() {
        alert('test worked!')
      }
    
      render() {
        return <div>Uploader</div>
      }
    }
    
    const App = () => {
      const theRef = React.useRef()
    
      const handleSendMessage = () => {
        fetch('https://jsonplaceholder.typicode.com/todos/1').then(json=>{
          theRef.current.test()
        });
      }
    
      return (
        <div>
          <button onClick={handleSendMessage}>Test Me</button>
          <Uploader ref={theRef}/>
        </div>
      )
    }
    
    ReactDOM.render(<App />, document.getElementById('root'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
    <div id="root"></div>

    【讨论】:

    • 嘿,我没有投反对票,不知道是谁投的。我几乎没有读过它,我会试一试,如果它成功了会告诉你
    • 嗯,这很奇怪。因为从本质上讲,这准确地说明了我正在尝试做的事情,但是这对我不起作用,如果它有这个问题就永远不会存在。我不确定为什么它在您的示例中有效,但在我的代码中无效,它本质上是一回事。修复它的是使用 useRef() 钩子而不是 createRef() func
    • 我也没有投反对票,但我可能会说原因可能是因为您的答案与 OP 的问题完全相同。所以它不会起作用,否则为什么 OP 会首先问这个问题。
    猜你喜欢
    • 2023-03-21
    • 1970-01-01
    • 2019-11-16
    • 1970-01-01
    • 2013-12-24
    • 1970-01-01
    • 2019-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多