【问题标题】:Cancel a fetch request in react-native在 react-native 中取消 fetch 请求
【发布时间】:2019-05-13 23:08:39
【问题描述】:

有什么方法可以中止 react-native 应用上的 fetch 请求?

class MyComponent extends React.Component {
  state = { data: null };

  componentDidMount = () =>
    fetch('http://www.example.com')
      .then(data => this.setState({ data }))
      .catch(error => {
        throw error; 
      });

  cancelRequest = () => {
   //???
  };

  render = () => <div>{this.state.data ? this.state.data : 'loading'}</div>;
}

我尝试了 AbortController 类中的 abort 函数,但它不起作用!!

...
abortController = new window.AbortController();

cancelRequest =  () => this.abortController.abort();

componentDidMount = () =>
        fetch('http://www.example.com', { signal: this.abortController.signal })
          ....

请帮忙!

【问题讨论】:

标签: android react-native fetch


【解决方案1】:

你不再需要任何 polyfill 来中止 React Native 0.60 changelog中的请求

这是来自 react-native 的 doc 的一个简单示例:

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow
*/

'use strict';

const React = require('react');
const {Alert, Button, View} = require('react-native');

class XHRExampleAbortController extends React.Component<{}, {}> {
  _timeout: any;

  _submit(abortDelay) {
    clearTimeout(this._timeout);
    // eslint-disable-next-line no-undef
    const abortController = new AbortController();
    fetch('https://facebook.github.io/react-native/', {
      signal: abortController.signal,
    })
      .then(res => res.text())
      .then(res => Alert.alert(res))
      .catch(err => Alert.alert(err.message));
    this._timeout = setTimeout(() => {
          abortController.abort();
    }, abortDelay);
  }

  componentWillUnmount() {
    clearTimeout(this._timeout);
  }

  render() {
    return (
      <View>
        <Button
          title="Abort before response"
          onPress={() => {
            this._submit(0);
          }}
        />
        <Button
          title="Abort after response"
          onPress={() => {
            this._submit(5000);
          }}
        />
      </View>
    );
  }
}

module.exports = XHRExampleAbortController;

【讨论】:

    【解决方案2】:

    我实际上已经写了很多关于这个主题的文章。 您还可以找到我打开的关于OLD React Native 中缺少 AbortController 的第一个问题here

    支持登陆 RN 0.60.0,您可以在我的博客 an article about thisanother one that will give you a simple code 上找到帮助您开始在 React Native 中发出可中止请求(以及更多)。它还为不支持的环境(例如 RN

    【讨论】:

    • 其实最好把代码放在这里,另外加上文章的链接,可以更深入的理解。
    【解决方案3】:

    最好的解决方案是使用 rxjs observables + axios/fetch 代替 promise,中止请求 => 取消订阅 observable:

    import Axios from "axios";
    import {
        Observable
    } from "rxjs";
    
    export default class HomeScreen extends React.Component {
        subs = null;
    
        doStuff = () => {
            let observable$ = Observable.create(observer => {
                Axios.get('https://jsonplaceholder.typicode.com/todos', {}, {})
                    .then(response => {
                        observer.next(response.data);
                        observer.complete();
                    })
            });
    
            this.subs = observable$.subscribe({
                next: data => console.log('[data] => ', data),
                complete: data => console.log('[complete]'),
            });
    
        }
    
        cancel = () =>
            if (this.subs) this.subs.unsubscribe()
    
        componentWillUnmount() {
            if (this.subs) this.subs.unsubscribe();
        }
    
    }
    

    就是这样:)

    【讨论】:

    • 那不会取消底层的 axios 请求。只是订阅结果。
    【解决方案4】:

    您实际上可以通过安装这个 polyfill abortcontroller-polyfill 来实现这一点 下面是一个取消请求的简单示例:

    import React from 'react';
    import { Button, View, Text } from 'react-native';
    import 'abortcontroller-polyfill';
    
    export default class HomeScreen extends React.Component {
      state = { todos: [] };
    
      controller = new AbortController();
    
      doStuff = () => {
        fetch('https://jsonplaceholder.typicode.com/todos',{
          signal: this.controller.signal
        })
        .then(res => res.json())
        .then(todos => {
          alert('done');
          this.setState({ todos })
        })
        .catch(e => alert(e.message));
        alert('calling cancel');
        this.controller.abort()
      }
    
    
      render(){
        return (
          <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
            <Text>Details Screen</Text>
            <Button title="Do stuff" onPress={() => { this.doStuff(); }} /> 
          </View>
        )
      }
    }
    

    所以基本上在这个例子中,一旦你点击“doStuff”按钮,请求会立即被取消,你永远不会收到“完成”警报。可以肯定的是,它有效,请尝试注释掉这些行并再次单击该按钮:

    alert('calling cancel');
    this.controller.abort()
    

    这一次您将收到“完成”提醒。

    这是一个简单的锄头示例,您可以在 react native 中使用 fetch 取消请求,请随意将其应用于您自己的用例。

    这里是snackexpo上的演示链接https://snack.expo.io/@mazinoukah/fetch-cancel-request

    希望对你有帮助:)

    【讨论】:

    • 这不起作用,我收到此错误消息:可能未处理的 Promise Rejection (id: 0): [AbortError: Aborted]
    • 来自文档:- 当请求被中止时,这个“polyfill”实际上并没有关闭连接,但它会用 err.name == 'AbortError' 而不是 .catch() 调用。然后()
    猜你喜欢
    • 2015-07-06
    • 2020-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多