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

如何创建点击自动禁用、执行结束恢复的React可复用按钮,解决卸载组件状态更新报错

解决方案

你遇到的报错本质是异步任务未完成时组件已卸载,此时调用setState就会触发警告,我们通过增加组件挂载状态标记来避免卸载后的状态更新。

修改BaseButton组件代码

import React from 'react';
export default class BaseButton extends React.Component {
  constructor(props) {
    super(props);
    // 挂载状态标记,不放在state中,无需触发渲染
    this._isMounted = false;
    this.state = {
      // 初始禁用状态取传入参数
      disabled: props.disabled,
      // 自定义点击处理函数
      customOnPress: props.onPress,
     };
  }

  componentDidMount() {
    // 组件挂载完成后标记为已挂载
    this._isMounted = true;
  }

  componentWillUnmount() {
    // 组件卸载前标记为已卸载
    this._isMounted = false;
  }

  /**
   * 点击事件包装函数
   */
  onPressWrapper = async () => {
    if (this.state.disabled) return;
    this.setState({ disabled: true });
    if (this.state.customOnPress != null) {
      await this.state.customOnPress();
    }
    // 仅组件仍处于挂载状态时才更新按钮状态
    if (this._isMounted) {
      this.setState({ disabled: false });
    }
  };

  // 修正状态更新逻辑,不直接修改state
  setNewOnPress = (inPress) => {
    this.setState({ customOnPress: inPress });
  };
  // 修正状态更新逻辑,不直接修改state
  setDisabled = (isDisabled) => {
    this.setState({ disabled: isDisabled });
  };
}

关键修改点说明

  • 新增_isMounted实例标记:用来跟踪组件当前是否处于挂载状态,避免对已卸载组件执行状态更新
  • 新增生命周期钩子:componentDidMount中标记组件已挂载,componentWillUnmount中标记组件已卸载
  • 优化onPressWrapper逻辑:执行完自定义异步函数后,先判断组件是否仍挂载,仅挂载状态下才恢复按钮可点击状态
  • 修正原有状态更新错误:原来的setNewOnPress和setDisabled方法直接修改this.state不符合React规范,改为调用setState实现状态更新,避免潜在的渲染异常

ButtonWithDisable组件优化(可选)

原代码中render方法直接修改this.props.onPress不符合React单向数据流规范,可做如下优化,使用方式保持不变:

import React from 'react';
import BaseButton from './BaseButton';
import { Fa, InputHolder, Text, TextInput } from './ButtonStyles';

class ButtonWithDisable extends BaseButton {
  render() {
    return (
      <InputHolder {...this.props} disabled={this.state.disabled} onPress={this.onPressWrapper}>
        <TextInput {...this.props}>
          {this.props.fa ? <Fa name={this.props.fa} {...this.props} children={undefined} /> : null}
          {this.props.icon ? this.props.icon : null}
          <Text {...this.props}>{this.props.children}</Text>
        </TextInput>
      </InputHolder>
    );
  }
}
export default ButtonWithDisable;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 19:36:04