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

react-native-camera扫码器因扫描过快冻结问题求助

我之前在做React Native条码扫描功能时,也踩过和你几乎一模一样的坑——用react-native-camera扫完跳转,返回时扫描器疯狂触发甚至冻结,还报那个讨厌的Can't call setState (or forceUpdate) on an unmounted component错误。结合我的解决经验,给你几个靠谱的方案:

1. 给扫描器加「激活状态开关」,绑定页面焦点事件

问题核心之一是:返回扫描页面时,组件还没完全就绪,扫描器就自动启动并识别了残留的二维码,同时可能还在尝试给已经卸载的组件更新状态。我们可以通过控制扫描器的激活状态,只在页面真正处于前台时开启扫描。

函数组件方案(用useFocusEffect)

import { useFocusEffect } from '@react-navigation/native';
import React, { useState, useCallback } from 'react';
import { RNCamera } from 'react-native-camera';

const ScannerScreen = ({ navigation }) => {
  // 控制扫描器是否激活
  const [isScanningActive, setIsScanningActive] = useState(false);

  // 监听页面焦点:进入页面开启扫描,离开页面关闭扫描
  useFocusEffect(
    useCallback(() => {
      setIsScanningActive(true);
      return () => {
        setIsScanningActive(false);
      };
    }, [])
  );

  const handleBarCodeScan = ({ data }) => {
    // 扫描未激活时直接返回,避免重复触发
    if (!isScanningActive) return;
    
    // 先关闭扫描,防止跳转前重复识别
    setIsScanningActive(false);
    // 跳转到目标页面
    navigation.navigate('TargetScreen', { qrContent: data });
  };

  return (
    <RNCamera
      // 只有激活状态下才绑定扫描回调
      onBarCodeRead={isScanningActive ? handleBarCodeScan : undefined}
      // 其他相机配置props...
    />
  );
};

类组件方案(监听导航事件)

import React from 'react';
import { RNCamera } from 'react-native-camera';

class ScannerScreen extends React.Component {
  state = {
    isScanningActive: false
  };

  componentDidMount() {
    // 监听页面聚焦事件
    this.focusListener = this.props.navigation.addListener('focus', () => {
      this.setState({ isScanningActive: true });
    });
    // 监听页面失焦事件
    this.blurListener = this.props.navigation.addListener('blur', () => {
      this.setState({ isScanningActive: false });
    });
  }

  componentWillUnmount() {
    // 移除监听
    this.focusListener();
    this.blurListener();
  }

  handleBarCodeScan = ({ data }) => {
    if (!this.state.isScanningActive) return;
    
    this.setState({ isScanningActive: false });
    this.props.navigation.navigate('TargetScreen', { qrContent: data });
  };

  render() {
    return (
      <RNCamera
        onBarCodeRead={this.state.isScanningActive ? this.handleBarCodeScan : undefined}
        // 其他相机配置props...
      />
    );
  }
}
2. 完善Axios请求的取消逻辑,确保彻底终止

你已经在componentWillUnmount里取消请求,但可能存在取消令牌绑定不严谨的情况。这里给你一个更稳妥的实现方式:

类组件示例

import axios from 'axios';

class TargetScreen extends React.Component {
  // 保存取消令牌源
  cancelRequestSource = axios.CancelToken.source();

  componentDidMount() {
    this.fetchData();
  }

  componentWillUnmount() {
    // 取消请求,并标注原因
    this.cancelRequestSource.cancel('组件已卸载,终止API请求');
  }

  fetchData = async () => {
    try {
      const response = await axios.get('/your-api-endpoint', {
        // 绑定取消令牌
        cancelToken: this.cancelRequestSource.token
      });
      // 处理接口返回数据
    } catch (error) {
      // 区分取消请求和其他错误
      if (axios.isCancel(error)) {
        console.log('请求已正常取消:', error.message);
      } else {
        // 处理其他网络/业务错误
      }
    }
  };

  // 其他页面逻辑...
}

函数组件示例

import axios from 'axios';
import { useEffect, useRef } from 'react';

const TargetScreen = () => {
  const cancelSourceRef = useRef(axios.CancelToken.source());

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await axios.get('/your-api-endpoint', {
          cancelToken: cancelSourceRef.current.token
        });
        // 处理数据
      } catch (error) {
        if (axios.isCancel(error)) {
          console.log('请求已取消');
        }
      }
    };

    fetchData();

    // 清理函数:组件卸载时取消请求
    return () => {
      cancelSourceRef.current.cancel('组件卸载,取消请求');
    };
  }, []);

  // 其他页面逻辑...
};
3. 可选:给扫描器加个初始化延迟

如果返回页面时相机组件还没完全初始化完成,可以给扫描激活加个小延迟,避免识别异常:

useFocusEffect(
  useCallback(() => {
    const timer = setTimeout(() => {
      setIsScanningActive(true);
    }, 300); // 延迟300ms,可根据实际情况调整

    return () => {
      clearTimeout(timer);
      setIsScanningActive(false);
    };
  }, [])
);
总结

最核心的解决思路是严格控制扫描器的生命周期:只有当页面处于前台、组件完全就绪时才开启扫描,离开页面立刻关闭;同时确保API请求能在组件卸载时彻底终止,避免异步操作触发已卸载组件的状态更新。这两个点结合起来,基本就能解决你遇到的冻结和报错问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:17:49