You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

当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)
        }
    }
}}

额外建议

  1. 若onSave中的API请求可能失败,要在onSave的catch块里抛出错误,确保组件能捕获到并重置状态;
  2. 可以给oneShot模式添加基础防抖逻辑,进一步避免重复触发;
  3. 所有异步操作完成后(无论成功、失败还是验证不通过),都必须确保isLoading被重置,防止状态不一致。

内容的提问来源于stack exchange,提问作者scipilot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 22:55:16