Skip to content

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

Open
@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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions