反应本地(expo)加载降价文件 [英] react native (expo) load markdown files

查看:46
本文介绍了反应本地(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>
    );
  }
}


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


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

https://论坛.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"

Unable to resolve "./assets/markdown/test-1.md" from "App.js"

您需要将@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"]
    },
    ...
  }
}

回答@Norfeldt的评论:尽管我在处理自己的项目时使用 react-native init ,因此我对Expo不太熟悉,但是我得到了这个Expo Snack,它可能为您提供了一些答案:

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)加载降价文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆