本文介绍了反应原生(expo)加载降价文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在将 Markdown 文件 (.md) 加载到我的 react native(非分离的 expo 项目)中时遇到了一些问题.

I'm having some troubles loading markdown files (.md) into my react native (non-detached expo project).

找到了这个很棒的包,可以让我渲染它.但不知道如何将本地 .md 文件加载为字符串.

Found this awesome package that allows me to render it. But can't figure out how to load the local .md file as a string.

import react from 'react';
import {PureComponent} from 'react-native';
import Markdown from 'react-native-markdown-renderer';

const copy = `# h1 Heading 8-)

| Option | Description |
| ------ | ----------- |
| data   | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext    | extension to be used for dest files. |
`;

export default class Page extends PureComponent {

  static propTypes = {};
  static defaultProps = {};

  render() {
    return (
        <Markdown>{copy}</Markdown>
    );
  }
}

顺便说一句:我尝试使用谷歌搜索,但无法获得建议


BTW: I tried googling, but can't get the suggestions to work

https://forums.expo.io/t/loading-non-media-assets-markdown/522/2?u=norfeldtconsulting

我在 SO 上尝试了 reactjs 的建议答案,但问题似乎是它只接受 .js.json 文件

I tried the suggested answers for reactjs on SO, but the problem seems to be that it only accepts .js and .json files

推荐答案

感谢@Filipe 的回复,我得到了一些指导,并得到了一个可以满足您需求的工作示例.

Thanks to @Filipe's response, I got some guidance and got a working example that will fit your needs.

就我而言,我在 assets/markdown/ 文件夹中有一个 .md 文件,该文件名为 test-1.md

In my case, I had a .md file on the assets/markdown/ folder, the file is called test-1.md

诀窍是获取文件的本地 url,然后使用 fetch API 将其内容作为 string 获取.

The trick is to get a local url for the file, and then use the fetch API to get its content as a string.

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Markdown from 'react-native-markdown-renderer';
const copy = `# h1 Heading 8-)

| Option | Description |
| ------ | ----------- |
| data   | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext    | extension to be used for dest files. |
`;

export default class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      copy: copy
    }
  }

  componentDidMount() {
    this.fetchLocalFile();
  }

  fetchLocalFile = async () => {
    let file = Expo.Asset.fromModule(require("./assets/markdown/test-1.md"))
    await file.downloadAsync() // Optional, saves file into cache
    file = await fetch(file.uri)
    file = await file.text()

    this.setState({copy: file});
  }


  render() {
    return (
        <Markdown>{this.state.copy}</Markdown>
    );
  }
}

为了摆脱错误

无法从App.js"解析./assets/markdown/test-1.md"

您需要将@Filipe 片段的 packagerOpts 部分添加到您的 app.json 文件中.

you would need to add the packagerOpts part of @Filipe's snippet into your app.json file.

app.json

{
  "expo": {
    ...
    "assetBundlePatterns": [
      "**/*"
    ],
    "packagerOpts": {
      "assetExts": ["md"]
    },
    ...
  }
}

编辑 2:回答@Norfeldt 的评论:虽然我在处理自己的项目时使用 react-native init,因此我对 Expo 不是很熟悉,但我得到了这个 Expo Snack,它可能会为您提供一些答案:https://snack.expo.io/Hk8Ghxoqm.

EDIT 2:Answering to @Norfeldt's comment:Although I use react-native init when working on my own projects, and I'm therefore not very familiar with Expo, I got this Expo Snack that might have some answers for you: https://snack.expo.io/Hk8Ghxoqm.

由于读取非 JSON 文件的问题,它不适用于博览会小吃,但如果您愿意,可以在本地进行测试.

It won't work on the expo snack because of the issues reading non-JSON files, but you can test it locally if you wish.

使用 file.downloadAsync() 将阻止应用程序对在该应用程序会话中托管您的文件的服务器进行 XHR 调用(只要用户不关闭并重新打开应用程序)).

Using file.downloadAsync() will prevent the app making XHR calls to a server where your file is hosted within that app session (as long as the user does not close and re-open the app).

如果您更改文件或修改文件(通过调用 Expo.FileSystem.writeAsStringAsync() 模拟),只要您的组件重新渲染并重新下载文件.

If you change the file or modify the file (simulated with a call to Expo.FileSystem.writeAsStringAsync()), it should display the updated as long as your component re-renders and re-downloads the file.

每次关闭并重新打开您的应用程序时都会发生这种情况,因为就我而言,file.localUri 不会在每个会话中持续存在,因此您的应用程序将始终调用 file.downloadAsync() 每次打开时至少一次.所以显示更新的文件应该没有问题.

This will happen every time your app is closed and re-open, as the file.localUri is not persisted per sessions as far as I'm concerned, so your app will always call file.downloadAsync() at least once every time it's opened. So you should have no problems displaying an updated file.

我还花了一些时间来测试使用 fetch 与使用 Expo.FileSystem.readAsStringAsync() 的速度,它们的平均速度是相同的.Expo.FileSystem.readAsStringAsync 通常快了约 200 毫秒,但在我看来,这并不是什么大问题.

I also took some time to test the speed of using fetch versus using Expo.FileSystem.readAsStringAsync(), and they were on average the same. Often times Expo.FileSystem.readAsStringAsync was ~200 ms faster, but it 's not a deal breaker in my opinion.

我创建了三种不同的方法来获取同一个文件.

I created three different methods for fetching the same file.

export default class MarkdownRenderer extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      copy: ""
    }
  }

  componentDidMount() {
    this.fetch()
  }

  fetch = () => {
    if (this.state.copy) {
      // Clear current state, then refetch data
      this.setState({copy: ""}, this.fetch)
      return;
    }
    let asset = Expo.Asset.fromModule(md)
    const id = Math.floor(Math.random()  * 100) % 40;
    console.log(`[${id}] Started fetching data`, asset.localUri)
    let start = new Date(), end;

    const save = (res) => {
      this.setState({copy: res})
      let end = new Date();
      console.info(`[${id}] Completed fetching data in ${(end - start) / 1000} seconds`)
    }

    // Using Expo.FileSystem.readAsStringAsync.
    // Makes it a single asynchronous call, but must always use localUri
    // Therefore, downloadAsync is required
    let method1 = () => {
      if (!asset.localUri) {
        asset.downloadAsync().then(()=>{
          Expo.FileSystem.readAsStringAsync(asset.localUri).then(save)
        })
      } else {
        Expo.FileSystem.readAsStringAsync(asset.localUri).then(save)
      }
    }

    // Use fetch ensuring the usage of a localUri
    let method2 = () => {
      if (!asset.localUri) {
        asset.downloadAsync().then(()=>{
          fetch(asset.localUri).then(res => res.text()).then(save)
        })
      } else {
        fetch(asset.localUri).then(res => res.text()).then(save)
      }
    }

    // Use fetch but using `asset.uri` (not the local file)
    let method3 = () => {
      fetch(asset.uri).then(res => res.text()).then(save)
    }

    // method1()
    // method2()
    method3()
  }

  changeText = () => {
    let asset = Expo.Asset.fromModule(md)
    Expo.FileSystem.writeAsStringAsync(asset.localUri, "Hello World");
  }

  render() {
    return (
        <ScrollView style={{maxHeight: "90%"}}>
          <Button onPress={this.fetch} title="Refetch"/>
          <Button onPress={this.changeText} title="Change Text"/>
            <Markdown>{this.state.copy}</Markdown>
        </ScrollView>
    );
  }
}

只需在三者之间交替以查看日志中的差异.

Just alternate between the three to see the difference in the logs.

这篇关于反应原生(expo)加载降价文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-27 14:09