React Native投币金额累加至2欧元的实现方案咨询
解决React Native投币箱金额累加问题
问题根源
你当前代码里用普通变量coinInserted和totalCoin存储累计金额,这些变量会在组件每次渲染时重置为初始值,导致无法持续累加每次投入的硬币金额。另外条件判断逻辑也存在冗余,需要优化。
解决方案
- 用
useState管理累计金额:React状态变量会在组件生命周期中保持值,不会随渲染重置。 - 优化金额累加逻辑:使用函数式更新状态,确保每次累加都基于最新的累计值。
- 处理浮点数精度:由于欧元硬币面值是小数点后两位,累加时可通过乘以100转成整数计算,避免浮点数精度误差。
- 重置金额时机:初始化投币箱时重置累计金额,确保每次支付流程从头开始。
修改后的完整代码
import {useNavigation} from '@react-navigation/native'; import React, {useEffect, useState} from 'react'; import { Alert, NativeEventEmitter, NativeModules, Pressable, StyleSheet, Text, View, } from 'react-native'; const {CoinBoxCollector} = NativeModules; export default function HomeScreen() { const navigation = useNavigation(); // 用state管理累计投币金额,初始为0 const [totalInserted, setTotalInserted] = useState<number>(0); const targetAmount = 2; // 目标支付金额2欧元 async function onCoinDetected(coin: any) { const coinValue = parseFloat(coin); // 过滤无效面值(可选,根据硬件返回情况调整) if (isNaN(coinValue)) return; // 先计算新的累计金额,用整数计算避免精度问题 const newTotal = Math.round((totalInserted + coinValue) * 100) / 100; if (newTotal >= targetAmount) { console.log("hai pagato per l' esperienza"); setTotalInserted(newTotal); // 更新最后一次金额 await CoinBoxCollector.stop(); // navigation.navigate('VideoScreen'); // 支付完成后导航到对应页面 // 支付完成后重置金额,方便下次使用 setTimeout(() => setTotalInserted(0), 1000); return; } // 未达到目标金额,更新累计值 setTotalInserted(newTotal); console.log(`DEVI INSERIRE ALTRI SOLDI: ${newTotal} / ${targetAmount} €`); } const pressInit = async () => { // 初始化时重置累计金额 setTotalInserted(0); await CoinBoxCollector.initialize(); }; const pressStop = async () => { console.log('getttoniera stoppata'); await CoinBoxCollector.stop(); // 停止时重置金额 setTotalInserted(0); }; useEffect(() => { const eventEmitter = new NativeEventEmitter(NativeModules.CoinBoxCollector); const eventListener = eventEmitter.addListener( 'onReceivedCoin', onCoinDetected, ); // 组件卸载时移除监听 return () => eventListener.remove(); }, [totalInserted]); // 依赖totalInserted确保监听逻辑正确 return ( <View style={styles.container}> {/* 显示当前累计金额 */} <Text style={styles.amountText}> 累计投币: {totalInserted.toFixed(2)} € / {targetAmount.toFixed(2)} € </Text> <Pressable style={styles.btn} onPress={pressInit}> <Text style={styles.btnText}>Initialize</Text> </Pressable> <Pressable style={styles.btn} onPress={pressStop}> <Text style={styles.btnText}>Stop it</Text> </Pressable> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, btn: { marginTop: 30, backgroundColor: '#841584', width: 120, height: 40, justifyContent: 'center', alignItems: 'center', borderRadius: 4, }, btnText: { color: 'white', fontSize: 16, }, amountText: { fontSize: 18, marginBottom: 20, }, });
关键修改点说明
- 将
coinInserted替换为useState定义的totalInserted,保证金额在组件渲染时不会丢失。 - 使用
Math.round((totalInserted + coinValue) * 100) / 100处理浮点数精度,避免出现0.30000000000000004这类异常值。 - 在
pressInit和pressStop中重置累计金额,确保每次操作都是全新的支付流程。 - 添加了累计金额的显示,方便用户查看当前投币进度。
- 修正了原有的条件判断逻辑,简化为判断新的累计金额是否达到目标值。
内容的提问来源于stack exchange,提问作者greta calamari
相关产品推荐
相关产品推荐

