如何创建点击自动禁用、执行结束恢复的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
相关产品推荐
相关产品推荐

