【发布时间】:2020-09-03 14:35:27
【问题描述】:
我已经查看此错误 2 天了,但我似乎无法弄清楚它是如何以及为什么不起作用。我的应用程序中有一个 FlatList 的 ProductComponent 元素,可以通过推送在 ProductComponent 中定义的 TouchableHighlight 组件进行买卖。
下面是我的FlatList 组件的代码和它呈现的ProductComponent:
FlatList 组件:
const ProductList: React.FC = () => {
const energyResources = useSelector((state: RootState) => state.energyResources).asImmutable();
const dispatch = useDispatch<RootDispatch>();
const coins = useSelector((state: RootState) => state.coins).coins;
const purchaseItem = (item: IEnergyResource): void => {
if (coins > item.price) {
dispatch.energyResources.increaseAmountOwned(dispatch.energyResources, item);
dispatch.coins.buy(dispatch.coins, item.price);
Alert.alert(
'Gekocht!',
'Je hebt zojuist de energiebron ' + item.name + ' gekocht, ' +
'\nJe hebt nu nog €' + coins + ' Euro!'
);
} else {
Alert.alert(
'Niet gekocht',
'Sorry, je hebt niet genoeg geld om deze energiebron te kopen.'
);
}
};
const sellItem = (item: IEnergyResource): void => {
if (item.amountOwned > 0) {
dispatch.energyResources.decreaseAmountOwned(dispatch.energyResources, item);
dispatch.coins.sell(dispatch.coins, item.price);
Alert.alert(
'Verkocht!',
'De energiebron ' + item.name + ' is verkocht, ' +
'je hebt nu €' + coins + ' Euro.'
);
} else {
Alert.alert(
'Niet verkocht',
'Sorry, de energiebron ' + item.name + ' kon niet worden verkocht, ' +
'je hebt er geen in je bezit.'
);
}
};
return (
<FlatList
style={styles.list}
data={energyResources.toArray()}
renderItem={
({ item }) => <ProductComponent
resource={item}
onPurchase={purchaseItem}
onSell={sellItem}
canSell={item.amountOwned > 0}
/>
}
keyExtractor={(item) => item.name}
/>
);
}
购买和销售方法都在FlatList-组件中定义,然后传递给各个元素(我认为这比在ProductComponent 本身中定义函数并让每个渲染的项目调用状态更好)。
ProductComponent 组件:
export interface IProductProps {
resource: IEnergyResource;
onPurchase: Function;
onSell: Function;
canSell: boolean;
}
const styles = StyleSheet.create({
buttonRight: {
alignItems: 'center',
alignSelf: 'flex-end',
backgroundColor: Constants.Colors.DodgerBlue,
marginVertical: 5,
padding: 10,
width: 150
},
image: {
alignSelf: 'flex-start',
height: 100,
width: 100
},
listItem: {
borderBottomColor: Constants.Colors.Blue,
borderBottomWidth: 2,
flex: 1,
flexDirection: 'row',
marginLeft: 5,
marginBottom: 0,
paddingBottom: 5
},
productInfo: {
width: 300,
},
rightButtons: {
alignItems: 'center',
alignSelf: 'flex-end'
},
sell: {
backgroundColor: Constants.Colors.Red
},
textLeft: {
alignSelf: 'flex-start',
fontSize: 20,
}
});
const ProductComponent: React.FC<IProductProps> = (props) => {
return (
<View style={styles.listItem}>
<Image source={props.resource.image.image} width={50} height={50} style={styles.image} />
<View style={styles.productInfo}>
<Text style={styles.textLeft}>{props.resource.name}</Text>
<Text style={styles.textLeft}>€{props.resource.price}</Text>
<Text style={styles.textLeft}>Energiewaarde: {props.resource.energyValue} Watt</Text>
<Text style={styles.textLeft}>In bezit: {props.resource.amountOwned}</Text>
</View>
<View style={styles.rightButtons}>
<TouchableHighlight style={styles.buttonRight} onPress={() => props.onPurchase(props.resource)}>
{/* eslint-disable-next-line react-native/no-inline-styles */}
<Text style={{ color: Constants.Colors.White, fontWeight: 'bold', fontSize: 15 }}>Kopen</Text>
</TouchableHighlight>
<TouchableHighlight style={[styles.buttonRight, styles.sell]} disabled={props.canSell} onPress={() => props.onSell(props.resource)}>
{/* eslint-disable-next-line react-native/no-inline-styles */}
<Text style={{ color: Constants.Colors.White, fontWeight: 'bold', fontSize: 15 }}>Verkopen</Text>
</TouchableHighlight>
</View>
</View>
);
};
这些方法存在于 IProductProps 接口中,并且调用似乎有效(我得到了定义的Alert,就好像我确实购买了产品一样)。但是,在警报框中单击确定后,指定产品的计数器(在ProductComponent 中定义为props.resource.amountOwned)仍然为0,我无法销售相同的产品。
这些是我调用的状态模型中定义的方法:
/**
* Increases the amount of items the player owns.
*
* @param {List<IEnergyResource>} state - the current state of the app
* @param {IEnergyResource} item - the item which was bought
* @returns {List<IEnergyResource>} state
*/
function increaseAmountOwned(state: EnergyResourcesState, item: IEnergyResource): EnergyResourcesState {
const itemIndex = state.indexOf(item);
const newItem = {
amountOwned: item.amountOwned++,
...item
};
return state.set(itemIndex, newItem);
}
/**
* Decreases the amount of items the player owns.
*
* @param {List<IEnergyResource>} state - The current state of the app
* @param {IEnergyResource} item - the item which was sold
* @returns {List<IEnergyResource>} state
*/
function decreaseAmountOwned(state: EnergyResourcesState, item: IEnergyResource): EnergyResourcesState {
const itemIndex = state.indexOf(item);
const newItem = {
amountOwned: item.amountOwned--,
...item
} as IEnergyResource;
return state.set(itemIndex, newItem);
}
const initialState: IEnergyResource[] =
[
{
name:'Windmolen',
price: 15,
energyValue:20,
environmentValue:-15,
image:{
maxSize:{
width:0.2,
height:0.2,
},
image: images.windmill,
},
amountOwned: 0,
amountTotal: 30,
amountPlaced: 0,
location:{
x:0.05,
y:0
},
},{
name:'Watermolen',
price: 15,
energyValue:15,
environmentValue:-10,
image:{
maxSize:{
width:0.2,
height:0.2,
},
image: images.turbine
},
amountOwned: 0,
amountTotal: 30,
amountPlaced: 0,
location:{
x:0.05,
y:0.3
},
},{
name:'Zonnepaneel',
price: 15,
energyValue:10,
environmentValue:-5,
image:{
maxSize:{
width:0.2,
height:0.2,
},
image: images.solarPanel
},
amountOwned: 0,
amountTotal: 30,
amountPlaced: 0,
location:{
x:0.3,
y:0
},
}
]
const resources = {
state: List(initialState),
reducers: {
place:(state: EnergyResourcesState, name: string): EnergyResourcesState =>
state = doMutateEnergyResource(state, name, true),
remove:(state: EnergyResourcesState, name: string): EnergyResourcesState =>
state = doMutateEnergyResource(state, name, false),
increaseAmountOwned: increaseAmountOwned,
decreaseAmountOwned: decreaseAmountOwned
},
};
我正在使用Rematch Redux framework 处理状态。
这可能是我在这里忽略的一个小细节,因此非常感谢任何朝着正确方向提供的帮助或推动。
提前谢谢你!
【问题讨论】:
-
我的猜测是
increaseAmountOwned中的energyResources数组正在更新但没有重新创建。如果数组引用未更改,选择器可能会进行浅层比较并放弃。可以检查您是否发布increaseAmountOwned的代码。 -
@nipuna777
increaseAmountOwned的代码据我所知已经存在,它是最后一个代码块中的第一个函数! -
知道了。我之前一定错过了。我看到您使用
List来存储状态,它使用哪个库?您是否尝试过使用数组?此外,为了调试它,我会首先设置更多断点(或警报)以查看减速器是否再次调用渲染方法。如果您可以在 stackblitz 或类似网站上制作一个最小可重现的演示,我可以帮助进一步调试。 -
感谢@nipuna777 的帮助!我现在发现了问题(见答案)。我项目组中的其他人负责对状态管理器进行编程,他到处使用
List-objects。我也不知道为什么。
标签: typescript react-native redux