当NativeBase按钮 onPress 处理失败时重置isLoading属性
问题描述
封装了一个「一次性」按钮组件,拦截onPress事件后先设置isLoading状态,再调用原onPress处理函数。原本是为了在执行缓慢的API调用时,让按钮进入禁用的加载状态,既给用户UI反馈,也防止重复点击。
原onPress处理函数包含表单字段验证逻辑:验证失败时返回false,希望终止流程并让用户修正输入。但组件捕获到这个返回值后,调用setIsLoading(false)无法重置按钮状态,按钮一直处于加载旋转的禁用状态,控制台能看到cancelled loader日志,但状态无变化。
组件代码
import React, {useState} from "react" import {StyleSheet} from "react-native"; import {Button as ButtonNB, IButtonProps, useTheme} from "native-base" interface IMyButtonProps extends IButtonProps { oneShot?: boolean } const Button = (props: IMyButtonProps) => { const [isLoading, setIsLoading] = useState(false) const {colors} = useTheme() return <ButtonNB px="25" style={styles.button} isLoading={isLoading} spinnerPlacement="end" isLoadingText="Saving..." backgroundColor={colors['primary']['500']} {...props} onPress={event => { if (props.oneShot) setIsLoading(true) if (props.onPress) { if(!props.onPress(event)) { console.debug('cancelled loader') setIsLoading(false) // 此处代码未生效 } } }} /> } export default Button
调用代码
按钮使用示例
<Button onPress={() => onSave()} oneShot={true} testID="prepare-submit-button" > {saveSubjectButtonText} </Button>
处理函数实现
async function onSave(){ // 验证失败时返回false终止流程 if(!validate()){ return false } else { // 执行API请求、更新本地状态等操作 navigation.navigate('Home') } }
环境信息
- 测试环境:iOS
- 依赖版本:
"native-base": "~3.4", "react": "17.0.2", "react-dom": "~17.0.2", "react-native": "0.67.4",
解决方案
问题核心原因
onSave是异步函数,异步函数的返回值本质是Promise对象,而非直接返回false。组件里的判断逻辑!props.onPress(event)实际是在判断「Promise是否为假值」,但Promise始终是真值,导致setIsLoading(false)代码块根本不会执行,这就是按钮状态无法重置的原因。
具体修复方案
修改组件的onPress拦截逻辑,支持处理异步函数的返回值:
onPress={async (event) => { if (props.oneShot) setIsLoading(true) if (props.onPress) { try { // 等待异步函数执行完成,拿到实际返回值 const result = await props.onPress(event) if (!result) { console.debug('cancelled loader') setIsLoading(false) } } catch (error) { // 异步操作报错时也要重置加载状态,避免按钮卡死 setIsLoading(false) console.error('操作失败:', error) } } }}
额外建议
- 若
onSave中的API请求可能失败,要在onSave的catch块里抛出错误,确保组件能捕获到并重置状态; - 可以给
oneShot模式添加基础防抖逻辑,进一步避免重复触发; - 所有异步操作完成后(无论成功、失败还是验证不通过),都必须确保
isLoading被重置,防止状态不一致。
内容的提问来源于stack exchange,提问作者scipilot
相关产品推荐
相关产品推荐

