当您导航到另一个屏幕时,React-Native 事件监听器不会被取消注册

问题描述 投票:0回答:1

我是一名 React 开发人员,这是我第一次处理 React-Native,我遇到了这个烦人的问题,我已经被困了 2 天了。

我有这个组件:

imports

const OrderDetails = ({route}) => {
  const {OrderNumber} = route.params;
  const [items, setItems] = useState(null);
  const navigation = useNavigation();

   useEffect(() => {
    const fetchItemDetails = async () => {
      try {
        const response = await axios.get(
          `http://192.168.X.XX:5000/orders/${OrderNumber}`,
        );
        setItems(response.data);
        const handleScannerStatus = data => {
          onBarcodeScan(data.data, response.data.items);
        };

        RegisterScanner(handleScannerStatus);
      } catch (error) {
        console.log('error fetching order');
      }
    };
    fetchItemDetails();

    return () => {
      console.log('component unmounted');
      UnregisterScanner();
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [OrderNumber]);
  const onBarcodeScan = async (barcode, items) => {
    console.log("Scanning barcode from OrderDetails");
    const matchedProduct = items.find(item => barcode === item.tag);
    if (matchedProduct.Type === 'kit') {
      navigation.navigate('KitDetails', {
        OrderNumber,
        kit: matchedProduct,
      });
    } 
  };

  return (my jsx)
};

const styles = {...mystyles}
export default OrderDetails;

这个组件基本上获取订单并注册一个事件,该事件侦听我的本机模块发送的发射,每当它在订单中找到一个套件项目时,我们就会导航到 kitDetails 组件,如下所示:

improts


const KitDetailsScreen = ({route}) => {
  const {OrderNumber, kit} = route.params;

  useEffect(() => {
    let handleScannerStatus = data => {
      console.log('Logging Barcode From KitDetails');
    };

    RegisterScanner(handleScannerStatus);

    return () => {
      console.log('unregister here');
      UnregisterScanner();
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const tableHead = ['SKU', 'Fulfilled'];
  const tableData = kit.items.map(orderItem => [
    orderItem.sku,
    `${orderItem.Fulfilled}`,
  ]);

  return (jsx);
};

const styles = {...}
export default KitDetailsScreen;

另外,我认为这并不重要,但这也是事件监听器:

import {NativeEventEmitter, NativeModules} from 'react-native';

const {BarcodeScannerModule} = NativeModules;
const eventEmitter = new NativeEventEmitter(BarcodeScannerModule);

export const RegisterScanner = handleScannerStatus => {
  eventEmitter.addListener('onBarcodeScanned', handleScannerStatus);

  BarcodeScannerModule.registerScannerStatusListener();
};

export const UnregisterScanner = () =>
  BarcodeScannerModule.unregisterScannerStatusListener();

这两个屏幕看起来非常相似,但这不是重点。这里的问题是,每当我导航到 kitDetails 时,我仍然会看到来自 OrderDetails 的 console.logs,我希望每当我导航到 kitDetails 时,事件都会取消注册,并使其仅在 kitDetails 中可用,但导航可以在奇怪的是它没有这样做。

当我开始扫描 kitDetails 组件内部时,这是输出:

 LOG  Logging Barcode From OrderDetails
 LOG  Logging Barcode From KitDetails
 LOG  Logging Barcode From OrderDetails
 LOG  Logging Barcode From KitDetails
 LOG  Logging Barcode From OrderDetails
 LOG  Logging Barcode From KitDetails

它应该只显示 KitDetails 日志。 也许是因为我是反应原生的新手,我错过了一些东西或者不完全理解流程是如何工作的,如果你能给我一些指示,那就太好了。 如果需要,我也可以提供我的本机模块代码。

我尝试过但不起作用的事情是:

  1. 在同一组件内切换视图,但这并不适合我的情况。
  2. 在导航开关之前取消注册。
  3. 知道卸载是异步的,我尝试在 kitDetails 内部的注册中添加 setTimeout,但仍然能够看到两个组件的控制台日志。 感谢您的关注。
javascript reactjs react-native event-handling
1个回答
0
投票

您似乎面临这样一个问题:即使导航到 KitDetails 组件后,OrderDetails 组件中的事件侦听器仍然处于活动状态。发生这种情况是因为导航到另一个屏幕时不会触发 OrderDetails 组件的清理函数(该函数会取消注册事件侦听器)。

要解决此问题,您可以按照以下步骤操作:

将扫描仪事件侦听器的注册和取消注册移到组件外部,并在更高级别进行管理,例如在父组件或上下文中。

当离开 OrderDetails 组件时,使用导航事件触发清理函数。 您可以通过以下方式修改代码来实现此目的:

移动事件注册和注销: 不要在每个组件内注册和取消注册事件侦听器,而是在更高级别上进行,例如在父组件或上下文中。

导航触发清理功能: 利用导航事件(例如 React Navigation 中的 useFocusEffect)在离开 OrderDetails 组件时触发清理功能。

这是如何重构代码的示例(根据组件名称进行更改enter image description here):

© www.soinside.com 2019 - 2024. All rights reserved.