提问人:bi3ri 提问时间:11/14/2023 最后编辑:bi3ri 更新时间:11/17/2023 访问量:64
使用 Hooks 在交互式 React 代码中动态渲染 Markdown 内容(钩子数量/顺序不同问题!
Render dynamically Markdown Content in interactive React Code with Hooks (Different number/order of hooks problem!)
问:
你好!
我想创建一个移动应用程序,它呈现用 markdown 编写的内容,类似于 Obsidian。到目前为止,我成功地使用该库来渲染包含非交互式内容的 Markdown 页面,例如文本、图像和 son-on。现在我想添加带有自定义规则的交互式 Markdown 内容,例如地图视图,它需要钩子才能正常工作。由于页面可以根据用户输入进行更改,并且每个页面都有不同的(交互式)内容,因此我遇到了“渲染的钩子比之前渲染期间更多的钩子”的问题。react-native-markdown-display
解决这个问题的最佳策略是什么?
在玩的时候,我发现如果我创建两个 react 组件和 ,它们基本上是相同的组件,只是名称不同。我可以为每个组件提供不同的 Markdown 内容,并有条件地呈现一个或另一个,而不会出错。这是解决这个问题的好方法吗?如果是,react 如何区分 react 组件?我怎样才能为不同的交互式内容动态创建组件,而这些组件可以区分哪些 react?Markdown
Markdown1
Markdown
为每个 Markdown 页面动态创建一个屏幕是一个好的解决方案吗?react-navigation
编辑:在 React-Navigation 中,屏幕不能在运行时动态添加,但它不会改变原来的问题。
我详细阐述了 和 方法,发现您还可以分配密钥,这似乎以类似的方式工作。我在这里提出了一个关于这个问题的新问题Markdown
Markdown1
答:
我也拖入了同样的问题,但我通过拆分组件解决了
当错误发生时,代码如下:
import React, { useState } from 'react'
import { ScrollView, StyleSheet, Text, TouchableOpacity, View,
useWindowDimensions } from 'react-native';
import InsureIcon from './InsureIcon';
import { icons } from '../constants';
import InputText from './common/InputText';
import { ButtonLoad } from './common/ButtonLoad';
const InsureDetails = ({handleChange,proposerDetail}) => {
const [addMoreMembers,setAddMoreMembers]=useState(false)
const handleAddMember=()=>{
setAddMoreMembers(true)
}
return (
<ScrollView>
<Text style={{fontSize:35,fontFamily:'serif',fontWeight:'bold',
marginVertical:30,color:'#696ac3'}}>
Select members to insure
</Text>
<View style={styles.insurers}>
<InsureIcon icon={icons.person} type="self" />
<InsureIcon icon={icons.female} type="spouse" />
<InsureIcon icon={icons.son} type="son" />
<InsureIcon icon={icons.daughter} type="daughter" />
<InsureIcon icon={icons.father} type="father" />
<InsureIcon icon={icons.mother} type="mother" />
{addMoreMembers &&
<>
<InsureIcon icon={icons.father} type="grand-father" />
<InsureIcon icon={icons.mother} type="grand-mother" />
</>
}
{!addMoreMembers &&
<View style={{width:useWindowDimensions().width*.8,marginHorizontal:useWindowDimensions().width*.1}}>
<ButtonLoad onPress={()=>handleAddMember()} title='Add more members'/>
</View>}
</View>
<InputText
label="Age of Eldest Member"
icon={icons.calender}
id='age'
type={'numeric'}
onChangeText={({ value }) => handleChange(value, id='age')}
value={proposerDetail.age}
/>
</ScrollView>
);
};
export default InsureDetails
像这样拆分组件后没有出现错误
import React, { useState } from 'react'
import { ScrollView, StyleSheet, Text, TouchableOpacity, View,
useWindowDimensions } from 'react-native';
import InsureIcon from './InsureIcon';
import { icons } from '../constants';
import InputText from './common/InputText';
import { ButtonLoad } from './common/ButtonLoad';
const MoreMember=()=>{
return (
<>
<InsureIcon icon={icons.father} type="grand-father" />
<InsureIcon icon={icons.father} type="grand-father" />
</>
)
}
const AddMember=({handleAddMember})=>{
return <View style=
{{width:useWindowDimensions().width*.8,
marginHorizontal:useWindowDimensions().width*.1}}>
<ButtonLoad onPress={handleAddMember} title='Add more members'/>
</View>
}
const InsureDetails = ({handleChange,proposerDetail}) => {
const [addMoreMembers,setAddMoreMembers]=useState(false)
const handleAddMember=()=>{
setAddMoreMembers(true)
}
return (
<ScrollView>
<Text style={{ fontSize:35,fontFamily:'serif',fontWeight:'bold',
marginVertical:30,color:'#696ac3'}}>
Select members to insure
</Text>
<View style={styles.insurers}>
<InsureIcon icon={icons.person} type="self" />
<InsureIcon icon={icons.female} type="spouse" />
<InsureIcon icon={icons.son} type="son" />
<InsureIcon icon={icons.daughter} type="daughter" />
<InsureIcon icon={icons.father} type="father" />
<InsureIcon icon={icons.mother} type="mother" />
{addMoreMembers&& <MoreMember/>}
{!addMoreMembers && <AddMember handleAddMember={handleAddMember}/>
}
</View>
<InputText
label="Age of Eldest Member"
icon={icons.calender}
id='age'
type={'numeric'}
onChangeText={({ value }) => handleChange(value, id='age')}
value={proposerDetail.age}
/>
</ScrollView>
);
};
export default InsureDetails
评论
条件/动态渲染
你不能有条件地调用钩子。在循环中调用钩子,虽然我认为这可能是合法的,但至少也是阴暗的,应该避免。React Hooks 必须在每个组件渲染中以完全相同的顺序调用。在组件的顶层调用它们(即不要将其嵌套在组件 ifself 以外的任何内容中)。
我确实问过是否是钩子导致了错误,因为我想您做了如下操作:useState
if (showAnotherMarkdown) {
const [markdown, setMarkdown] = React.useState();
}
更改组件的状态
如何为不同的交互式内容动态创建 Markdown 组件
我对此一无所知,但我查看了他们的文档,似乎如果您想更改 Markdown 组件显示的内容,您只需为其提供不同的数据即可。假设你有两个常量来保存 markdown 和两个按钮,用于更改使用哪一个:react-native-markdown-display
const markdown1 = `# h1 This is a markdown`;
const markdown2 = `# h1 This is another markdown`;
const [markdown, setMarkdown] = React.useState(markdown1);
return (
<div>
My Markdown:
<Markdown>
{markdown}
</Markdown>
<Button onClick={() => setMarkdown(markdown1)}>
show first markdown
</Button>
<Button onClick={() => setMarkdown(markdown2)}>
show the other markdown
</Button>
</div>
);
这些不是常量,而是文件、从服务器获取的数据、用户输入 - 天空是极限。重要的是调用什么,这反过来又决定了什么位于状态中,然后传递给组件。setMarkdown
Markdown
呈现列表
如果需要根据某些任意数据显示一组不同的元素,可以通过多种方式实现。
您以状态保存数据,如下所示:
const [markdownList, setMarkdownList] = React.useState([]);
然后将数据映射到元素,例如:
return (
<div>
Markdown list:
{markdownList.map((markdown, index) => (
<Markdown key={index}>
{markdown}
</Markdown>
))}
</div>
);
我不知道你的 markdown 是从哪里来的,所以我只提供一种将一些添加到列表中的一般方法:
function addMarkdown(newMarkdown) {
setMarkdownList(prevList => [...prevList, newMarkdown]); //appending to the end
}
如果你将一个对象或数组保持在状态中,请确保每次要更新它时创建一个新对象或数组,因为 React 会比较引用以判断是否进行了更改,并且不检查它们的内容。
一个典型的例子是待办事项列表。我鼓励你看看一些例子。这是 codesandbox 上待办事项列表的完整示例。
组件树
React 如何区分 React 组件?
它创建一个虚拟 DOM 树。此树的元素与屏幕上显示的元素相对应。
此外,JSX 被转译为调用:React.createElement
const element = (
<h1 className="greeting">
Witaj, świecie!
</h1>
);
const element = React.createElement(
'h1',
{className: 'greeting'},
'Witaj, świecie!'
);
你可以看到它被传递给了,所以这是 React 区分组件的另一部分 - 通过用于创建 DOM 树的函数(或标签)。'h1'
createElement
在上面的示例中,我使用映射来创建任意一组元素。有一点需要注意。
直接在 map() 调用中的 JSX 元素总是需要键!
也用于区分元素。React 保存每个元素的数据,并且需要将状态分配给拥有它的元素。我用了as,只要你不对列表执行任何操作,除了添加到末尾之外,这很好。例如,如果要从列表的开头删除一个元素,并且索引会移动,则状态不会随之移动,并且第二个元素将从第一个元素获取状态,从第二个元素获取第三个元素,依此类推。需要是独一无二的。ID 和哈希值之所以好,是因为它们通常是唯一的。key
key
index
key
key
key
免責聲明
你没有提供和编码,所以我不得不猜测一些事情,我不确定我上面写的任何内容是否有任何帮助。请随时提出更深层次的问题。
评论