首页 > 解决方案 > 用于处理服务器响应的 React 和 React Native 模式

问题描述

过去,我在 Android(Java)和 iOS(ObjC 和 Swift)上进行了大量的原生移动开发。对于我的服务器连接应用程序,我必须正确处理的一个问题是应用程序发出 HTTP 请求后调用的回调。例如,假设我有一个屏幕(Android 中的 Activity 或 iOS 中的 ViewController),并且在其中我向 REST 服务器发出 HTTP 请求,期望得到一些数据作为响应。大多数教科书(不幸的是)都提供了在 Activity 或 ViewController 本身中调用回调方法的 HTTP 响应示例。是的,乍一看似乎是合理的,但在具有多个活动或视图控制器的应用程序中存在一个大问题 - 如果用户在请求之后但在响应返回之前离开屏幕会发生什么?在这种情况下,

相反,我们必须使用一个持久的单例对象(如在 Android 中扩展 Application 或在 iOS 中使用 appdelegate 的类)作为实现回调函数的类。任何想要获得结果的屏幕都必须注册这些结果(在 Android 中使用侦听器或在 iOS 中使用通知)。如果用户离开屏幕,屏幕的适当生命周期方法将在屏幕中取消注册侦听器/通知处理程序,这样就不会出现在释放内存时调用回调方法的情况。

现在我开始同时使用 React(在浏览器中)和 React Native(在移动应用程序中)。我正在使用 Axios 模块来处理 HTTP 请求。再一次,我看到的所有示例都显示了 React 组件本身中的回调,而不是任何类型的模式,其中存在某种持久的单例或全局对象来处理响应并将它们分派到显示器上仍处于活动状态的任何屏幕。

所以我有几个问题如下:

对于 React(在浏览器中),这是一个问题吗?我可以/应该只在组件本身上提供一个回调,如果我在请求中离开屏幕,浏览器不会有问题吗?我怀疑这些天浏览器代码非常健壮,所以我怀疑它会使浏览器崩溃,但它会导致 webapp 出现任何问题吗?

React Native 呢?由于这基本上是建立在移动原生代码之上的,如果我将回调放在组件本身中,我会遇到这个内存崩溃问题吗?

如果这是一个问题,是否有一个好的模式可用于中央全局持久对象来处理回调并将结果分派给任何已注册的组件?

请注意,我不会在我的代码中使用 redux - 相反,我计划使用一个更简单的框架(hookstate、hookstate.js.org),它可以让我跟踪全局状态并在更新时在组件内部使用它。这似乎有点像全局状态的回调系统,但我不太清楚通过 Axios 等模块将 HTTP 请求合并到其中的最佳模式。

建议?

标签: reactjsreact-nativeaxiosreact-hooks

解决方案


答案可能在很大程度上取决于您如何在应用程序中进行状态管理。但是,假设您使用的是支持钩子的 React Native 版本,这样的模式可能是一个有用的入门模式:

import React, {useState, useEffect} from 'react'
import axios, {CancelToken} from 'axios'

const MyComponent = () => {
  const [blah, setBlah] = useState(null)

  useEffect(() => {
    //Axios comes with support for cancelling. See here
    //https://github.com/axios/axios#cancellation
    const source = CancelToken.source();
    let source = null

    axios.get('/some/url', {cancelToken: source.token})
      .then(({data}) => {
        //If the request is successful, we know the component wasn't unmounted.
        //Go ahead and call the state-modifying function.
        setBlah(data)
      })
      .catch((thown) => {
        //If something goes wrong, check to see if it is because of a cancel.
        //If it is, we probalby don't need to do anything.
        if (axios.isCancel(thrown)) {
          console.log("Cancelled")
        }
        else {
          //Otherwise, we can handle the error gracefully
        }
      })
    //If you return a function from setEffect, it will be
    //executed when the component is about to unmount (componentWillUnmount)
    //See https://reactjs.org/docs/hooks-effect.html#example-using-hooks-1
    return () => source.cancel()
  }, []) //This will only run once (the first time the component renders)

  return <pre>{blah}</pre>
}

本质上,我们使用useEffect的是通过 Axios 触发请求。然后我们利用 Axios 的内置取消功能 ( https://github.com/axios/axios#cancellation )。当组件被卸载时,我们调用取消函数。结果,thenaxios 请求的子句不会执行。在这种特殊情况下,这并不重要。我们使用的是组件内部的状态,因此setBlah卸载后运行不会有任何影响。然而,如果说你使用 Redux 来实现全局状态,或者其他一些 reducer 模式,那么then即使在卸载之后,你的子句也可能会触发一些外部操作。

那么,要回答“重要”的问题吗?答案是“视情况而定”。如果您可以将您的状态保持在发出请求的组件的本地,也许不能。如果,就像您提到的那样,您计划拥有一些全局状态并公开修改该状态的方法(Redux,或公开减速器的上下文),那么它当然可以。如果您的组件被卸载,这样的模式应该避免调用状态修改函数。

警告 - 我没有测试过这段代码。其中大部分来自我提供的链接,希望这些链接可以提供任何必要的额外上下文(或者如果我的实现细节错误,则进行更正)。


推荐阅读