Skip to content

一个基于 React-Native 0.75 Expo 51 的成功案例。 #26

@ContinueOneSecond

Description

@ContinueOneSecond

首先感谢该项目的所有开源贡献者
环境:

  • React-Native 0.75
  • Expo 51

先说为什么还是选择了fetch:rn-sse、event-source 同样是非常优秀的开源项目,但是不太满足我的HttpRequest需求,以及EventSource会使我的Markdown混乱,我无法解决。

在我尝试了 axion、websocket、rn-sse、event-source 以及数个小时的调试和大量的翻译工作后,终于在这个项目中取得到了结果。

在各种论坛上徘徊后,我找到了该项目,以下是我最低限度的实践:

  1. 我安装了文档中所有的依赖,并且在项目根目录创建了 index.js
    这里有几个地方需要说明:
    import { polyfill as polyfillReadableStream } from 'react-native-polyfill-globals/src/readable-stream';
    web-streams-polyfill/ponyfill/es6 加载时会报错,于是我使用 const { ReadableStream } = require('web-streams-polyfill/dist/ponyfill.es5.js'); 代替

polyfillEncoding(); 使用 react-native-polyfill-globals 提供的

polyfillFetch(); 使用 react-native-polyfill-globals 提供的

参考:

https://stackoverflow.com/questions/56207968/stream-api-with-fetch-in-a-react-native-app/77089139#77089139
另外我遇到了一些其他上面的异常,但是介于当前是最小可行性的示例,不进行赘述。

index.js

// import 'react-native-polyfill-globals/auto';
// import { polyfill as polyfillBase64 } from 'react-native-polyfill-globals/src/base64';
// import { polyfill as polyfillReadableStream } from 'react-native-polyfill-globals/src/readable-stream';
// import { polyfill as polyfillURL } from 'react-native-polyfill-globals/src/url';
// import { polyfill as polyfillCrypto } from 'react-native-polyfill-globals/src/crypto';
import { polyfillGlobal } from 'react-native/Libraries/Utilities/PolyfillFunctions';
import { polyfill as polyfillEncoding } from 'react-native-polyfill-globals/src/encoding';
import { polyfill as polyfillFetch } from 'react-native-polyfill-globals/src/fetch';
const { ReadableStream } = require('web-streams-polyfill/dist/ponyfill.es5.js');
// 调用 polyfill 函数
polyfillFetch();
// polyfillReadableStream();
// polyfillBase64();
// polyfillURL();
// polyfillCrypto();
// polyfillFetch();
polyfillEncoding();

polyfillGlobal("ReadableStream", () => ReadableStream);
// polyfillGlobal(
//     "fetch",
//     () =>
//         (...args: any[]) =>
//             fetch(args[0], { ...args[1], reactNative: { textStreaming: true } }),
// );
// polyfillGlobal("Headers", () => Headers);
// polyfillGlobal("Request", () => Request);
// polyfillGlobal("Response", () => Response);
// polyfillGlobal('TextEncoder', () => TextEncoder);
// polyfillGlobal('TextDecoder', () => TextDecoder);

import "expo-router/entry";
  1. 请求示例
 static async post_stream(url: string, params?: Record<string, any>): Promise<ReadableStreamDefaultReader<Uint8Array>> {
        const token = await this.getToken();
        try {
            const response = await fetch(url, {
                method: 'post',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': token ? `Bearer ${token.token}` : '',
                    'Accept': 'text/event-stream'
                },
                //@ts-ignore
                reactNative: { textStreaming: true },
                body: JSON.stringify(params)
            });

            //检查普通异常
            checkStream(response);
            if (response.body === null) {
                throw new BizError("500", "网络错误,请稍后重试");
            }
            return response.body.getReader();
        } catch (error) {
            throw checkError(error);
        }
    }
  1. 解析示例
export const useStreamReader = async ({reader, onData,onOpen, onError, onComplete}: StreamReaderProps) => {
    let isReading = false;
    const decoder = new TextDecoder('utf-8');

    try {
        isReading = true;
        onOpen?.();
        while (isReading) {
            const {done, value} = await reader.read();
            console.log("org",value);
            if (done) {
                onComplete?.();
                break;
            }
            const decodedData = decoder.decode(value);
            console.log("before",decodedData)

            let strings = decodedData.split("data:");
            let res = "";
            strings.forEach((str) => {
                if(str === ''){
                    return;
                }
                if (str.endsWith("\n\n")) {
                    str = str.slice(0, -2);
                }
                const data = str.replace("data:","");
                res += data;
            })
            onData(res);
        }
    } catch (error) {
        console.error(error);
        isReading = false;
        onError?.(error);
    } finally {
        isReading = false;
        onComplete?.();
    }
}

希望可以帮助到有需要的人。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions