我在将markdown 文件(.md)加载到react native(非独立的expo项目)时遇到了一些问题.

找到了这个很棒的软件包,可以让我渲染它.但无法理解如何将本地.md文件作为字符串加载.

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>
    );
  }
}

顺便说一句:我试过用谷歌搜索,但没能让建议生效

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

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

推荐答案

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

在我的例子中,assets/markdown/文件夹中有一个.md文件,该文件名为test-1.md

诀窍是为文件获取本地url,然后使用fetch API将其内容获取为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部分添加到应用程序.json文件中.

应用程序.json

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

编辑2:

由于读取非JSON文件的问题,它在expo零食上不起作用,但如果您愿意,可以在本地测试它.

使用file.downloadAsync()将防止应用程序向该应用程序会话中承载您的文件的服务器发出XHR调用(只要用户不关闭并重新打开应用程序).

如果更改文件或修改文件(模拟调用Expo.FileSystem.writeAsStringAsync()),只要组件重新渲染并重新下载文件,它就会显示更新的文件.

每次关闭并重新打开你的应用程序时都会发生这种情况,因为就我而言,每次会话都不会保留file.localUri,所以每次打开你的应用程序时都会至少呼叫file.downloadAsync()一次.因此,显示更新的文件应该没有问题.

我还花了一些时间测试了使用fetch和使用Expo.FileSystem.readAsStringAsync()的速度,他们的平均速度是一样的.通常情况下,Expo.FileSystem.readAsStringAsync的速度要快约200毫秒,但在我看来,它并不是一个交易 destruct 者.

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

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>
    );
  }
}

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

React-native相关问答推荐

你如何使 react-native react-navigation 标签栏透明

Firebase JavaScript SDK 和 react-native-firebase 有什么区别

Soundcloud API /stream 端点给出 401 错误

Yarn 在哪里存储离线包?

React Native:自定义字体在 Android 和 iOS 上呈现不同

渲染时获取未定义不是 React Native 中的对象

React Native Expo StackNavigator 重叠通知栏

如何在react-native中设置 FlatList 的刷新指示器?

如何在 Text 中围绕 Text 包裹 TouchableOpacity?

等待模块失效的超时

ENOENT: no such file or directory, 打开 'android/app/src/main/assets/index.android.bundle'

如何将时刻日期转换为字符串并删除时刻对象

Expo LAN 配置不适用于新的 ReactNative 元素

React Native,AppStore 请求 NSLocationAlwaysUsageDescription 值

如何在 React Native 上隐藏 createStackNavigator 的标题?

React 本机矢量图标在当前版本 0.60 上不起作用

如何使用 Jest 测试导入自定义原生模块的 React Native 组件?

react-native iOS 应用在部署后不显示静态/本地资源

如何升级 react-native gradle 版本

React Native + Redux 基本认证