reactjs - 反应原生(expo)加载降价文件
问题描述
我在将 Markdown 文件.md
(
找到了这个很棒的包,可以让我渲染它。但无法弄清楚如何将本地.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
我在 SO 上尝试了 reactjs 的建议答案,但问题似乎是它只接受.js
和.json
文件
解决方案
感谢@Filipe 的回复,我得到了一些指导,并得到了一个可以满足您需求的工作示例。
就我而言,我在文件夹中有一个.md
文件assets/markdown/
,该文件称为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”
您需要将packagerOpts
@Filipe 片段的一部分添加到您的app.json
文件中。
应用程序.json
{
"expo": {
...
"assetBundlePatterns": [
"**/*"
],
"packagerOpts": {
"assetExts": ["md"]
},
...
}
}
编辑 2:回答@Norfeldt 的评论:虽然我react-native init
在自己的项目中使用,因此我对 Expo 不是很熟悉,但我得到了这个 Expo Snack,它可能对你有一些答案:https://snack.expo .io/Hk8Ghxoqm。
由于读取非 JSON 文件的问题,它不适用于博览会小吃,但如果您愿意,可以在本地对其进行测试。
使用file.downloadAsync()
将阻止应用程序对您的文件在该应用程序会话中托管的服务器进行 XHR 调用(只要用户不关闭并重新打开应用程序)。
如果您更改文件或修改文件(通过调用模拟Expo.FileSystem.writeAsStringAsync()
),只要您的组件重新渲染并重新下载文件,它就应该显示更新的内容。
每次关闭并重新打开您的应用程序时都会发生这种情况,因为file.localUri
就我而言,每个会话都不会持续存在,因此您的应用程序file.downloadAsync()
每次打开时都会至少调用一次。因此,显示更新的文件应该没有问题。
我还花了一些时间来测试 usingfetch
和 using的速度Expo.FileSystem.readAsStringAsync()
,它们的平均速度是一样的。通常Expo.FileSystem.readAsStringAsync
快 200 毫秒左右,但在我看来这不是一个交易破坏者。
我创建了三种不同的方法来获取同一个文件。
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>
);
}
}
只需在三者之间交替以查看日志中的差异。
推荐阅读
- java - 更改移动字体时应用程序字体更改
- android - 我有一个代码,其中检索 json 数据,现在我想处理不同的异常
- ios - 快速捕获自由形式的视图控制器屏幕截图
- javascript - Bootstrap 4 折叠,关闭所有其他可折叠项
- powershell - Windows 服务器中的 Wow632 注册表重定向
- r - 如何使用子集从数据框中删除行?
- c++ - VSCode C++ WSL 调试配置
- flutter - 如何在 Flutter 的 ListView.builder 中使用特定的小部件
- rust - 实现代数结构及其元素的最佳方法是什么?
- apache-kafka - 在什么情况下,即使产量为零,kafka 消费者的延迟也会突然飙升?