下面是我的代码。我如何让我的药水计数真实的更新,同时避免“比以前渲染更多的钩子”错误。
我知道有一种方法可以做到这一点,但我很难理解它是如何工作的。如果有人能很好地解释它,那将是伟大的,因为我将需要这种情况发生在我的建设很多。
import React, { useState } from 'react';
import { View, Text, Image, StyleSheet } from 'react-native';
import CustomButton from './CustomButton';
import { useFonts } from 'expo-font';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import player from './Player';
import usePotion from './UsePotion';
import { useNavigation } from '@react-navigation/native';
function addPotion() {
player.potions ++;
}
function BattleScreen() {
const [fontsLoaded, error] = useFonts({
'Valorax': require('./Fonts/Valorax.otf'),
});
const navigation = useNavigation()
const [potionMessage, setPotionMessage] = useState('');
if (!fontsLoaded) {
return <Text>Loading...</Text>;
}
return (
<View style={styles.container}>
<Text style={styles.text}>{player.potions}</Text>
{potionMessage && <Text style={styles.text}>{potionMessage}</Text>}
<View style={styles.topHalf}>
</View>
<View style={styles.bottomHalf}>
<View style={styles.buttonRow}>
<CustomButton onPress={() => handleAttack()} title='Attack'></CustomButton>
<CustomButton onPress={() => handleMagic()} title='Magic'></CustomButton>
</View>
<View style={styles.buttonRow}>
<CustomButton onPress={() => usePotion(setPotionMessage)} title='Use Potion'></CustomButton>
<CustomButton onPress={() => handleRun()} title='Run'></CustomButton>
<CustomButton onPress={() => navigation.navigate('Home')} title="Home"></CustomButton>
<CustomButton onPress={() => addPotion()} title="Add Potion"></CustomButton>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#000000',
},
topHalf: {
flex: 1,
color: 'white',
},
bottomHalf: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap'
},
buttonRow: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-evenly',
flexWrap: 'wrap'
},
text: {
fontSize: 40,
color: 'white',
fontFamily: "Valorax",
}
});
export default BattleScreen;
2条答案
按热度按时间blmhpbnm1#
我认为您看到的错误是由于在您的JSX中调用
usePotion
钩子造成的。钩子只能在其他钩子的顶层或其他组件的顶层调用。我不确定usePotion
与setPotionMessage
的关系。但是它需要在组件的顶层调用,如果你想从usePotion
触发某个事件,你需要从usePotion
返回它:现在你有了一个钩子,它返回一些关于药剂的状态,并允许你触发其他状态更新:
最后你需要让player进入react生命周期,你可以把Player.js转换成钩子,或者你可以把player放入state:
qjp7pelc2#
为了解决药剂计数不更新的问题,简短的答案是你必须使用一个
useState
钩子,简短的理由是因为react只会在状态改变时重新渲染,并且它足够聪明,只更新那些受状态改变影响的组件。代码中的一个示例是,当调用
setPotionMessage
方法并更新potionMessage
值时,react所做的唯一更新是针对JSX{potionMessage && <Text style={styles.text}>{potionMessage}</Text>}
。此数据需要存储在状态中的长期原因如下:当react最初呈现时,它会编译一个包含所有返回组件的DOM树。这个DOM树看起来与您编写的JSX非常相似,只是增加了一些父标记和其他东西。当且 * 仅当 * 状态发生变化时,React会编译一个新的DOM树。调用
Virtual DOM
,然后将现有的DOM树与新的虚拟DOM树进行比较,找出发生变化的组件,最后react将更新原始的DOM树,但是它 * 只 * 更新那些已经改变的组件。继续我上面使用的
potionMessage
示例,当BattleScreen
最初呈现时,Virtual DOM将如下呈现JSX(从return
语句中提取):但是,一旦调用了
setPotionMessage
,并且potionMessage
的值从''
变为一条消息,react就会重新编译Virtual DOM,以确定发生了什么变化。然后,它将原始DOM树与虚拟DOM树进行比较,找出不同之处,当发现不同之处时,它只重新呈现实际DOM树中发生变化的部分。
在代码修改方面,PhantomSpooks列出了需要的修改。正如他们提到的,让玩家进入React生命周期将是关键。