在 FlatList 中反应本机计数计时器

React Native Count up Timer inside FlatList

您好,我是 React Native 的新手,现在我正在尝试在每个 Flat List 行中创建计数计时器。基于数据时间戳与当前日期比较的计算。我的倒计时间隔适用于每一行,但现在的问题是性能。 Android 有时会导致 ANR(应用程序未响应)。

有什么建议可以改进这段代码吗?非常感谢任何帮助。 谢谢。

  import React, { useState, useEffect } from 'react'
    import { View, Text, ActivityIndicator, Modal, FlatList } from 'react-native'
    import Style from '../../../../constants/Style'
    import AsyncStorage from '@react-native-community/async-storage'
    import { API, Auth } from 'aws-amplify'
    import AWSMQTTConnection from '../../../../common/AWSMQTTConnection'
    import AsyncStorageConstants from '../../../../constants/AsyncStorageConstants'
    
    var isLeaving = false
    
    
    function EquipmentElement({ id, name, number, status, time, maintenanceCode }) {
    
        const [hours, setHours] = useState('00')
        const [minutes, setMinutes] = useState('00')
        const [seconds, setSeconds] = useState('00')
    
        var count = setInterval(() => {
            var now = new Date().getTime()
            var distance = now - time
    
            var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
            var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))
            var seconds = Math.floor((distance % (1000 * 60)) / 1000)
    
            var isHourLessThanTen = hours < 10
            var isMinuteLessThanTen = minutes < 10
            var isSecondLessThanTen = seconds < 10
    
            if (isHourLessThanTen) {
                hours = '0' + hours
            }
    
            if (isMinuteLessThanTen) {
                minutes = '0' + minutes
            }
    
            if (isSecondLessThanTen) {
                seconds = '0' + seconds
            }
    
    
            if ((status == 'Available' || status == undefined) || maintenanceCode == 1) {
                clearInterval(count)
            } else {
                if (isLeaving) {
                    clearInterval(count)
                } else {
                    setHours(hours)
                    setMinutes(minutes)
                    setSeconds(seconds)
                }
            }
    
        }, 1000)
    
    
        const setDurationValue = () => {
            if (maintenanceCode == 1) {
                <Text style={Style.value}>00:00:00</Text>
            } else {
                if (time != 0 || time != '' || time == undefined) {
                    return (<Text style={Style.value}>{hours}:{minutes}:{seconds}</Text>)
    
                } else {
                    return (<Text style={Style.value}>00:00:00</Text>)
                }
            }
        }
    
        return (
            <View style={Style.smartElementContainer}>          
                 {setDurationValue()}                  
            </View>
        )
    }
    
    function Equipment() {
    
        const [equipmentData, setEquipmentData] = useState([])
      
        useEffect(() => {
    
            isLeaving = false
            getEquipmentList(false)
    
            return function cleanup() {
                console.log('unmounting...')
                isLeaving = true
                setEquipmentData([])
            }
    
        }, [])

 const getEquipmentList = async (isMQTT) => {
        try {
           
            let propertyId = await AsyncStorage.getItem(AsyncStorageConstants.StorageConstants.CURRENT_PROPERTY_ID)
            let apiName = 'DemoAsiaIoT'
            let path = '/scdevice'
            let request = {
                headers: { Authorization: `Bearer ${(await Auth.currentSession()).getIdToken().getJwtToken()}` },
                response: true,
                queryStringParameters: {
                    propertyId: propertyId,
                    applicationId: 5
                }
            }

            await API.get(apiName, path, request).then(response => {
                var data = response.data.resultData
                var devices = []

                for (var i = 0; i < data.length; i++) {
                    var device = data[i]
                    devices.push({ id: device.deviceEUI, name: device.deviceName, number: '01', status: device.status, time: device.timestampStart, maintenanceCode: device.manualOverRide })
        
                }

                setEquipmentData(devices)
                
            }).catch(error => {
                console.log('Error from request - ', error.response)
            })


        } catch (err) {
            console.log('error:', err)
        }
    }

    
            return (
            <View style={{ flex: 1 }}>
                <FlatList
                    style={{
                        width: '100%',
                        marginTop: 10,
                    }}
                    showsVerticalScrollIndicator={false}
                    vertical={true}
                    data={equipmentData}
                    renderItem={({ item }) => <EquipmentElement id={item.id} name={item.name} number={item.number} status={item.status} time={item.time} maintenanceCode={item.maintenanceCode} />}
                    keyExtractor={item => item.id} />
            </View>
        )
    }
    
    export default Equipment

关于如何优化代码的一些建议。

  1. 您不需要使用 hoursminutesseconds 三种状态来显示您在 FlatList 项目中的时间。这些是 Date.now() 的推导。您可以查看下面的代码来理解这个概念。只需在 return 显示格式化时间的组件范围之外创建一个辅助函数。如果你这样做,你的大部分表现都可以解决。
function calculateTimeLeft() {
  const year = new Date().getFullYear();
  const difference = +new Date(`${year}-10-1`) - +new Date();
  let timeLeft = {};

  if (difference > 0) {
    timeLeft = {
      days: Math.floor(difference / (1000 * 60 * 60 * 24)),
      hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
      minutes: Math.floor((difference / 1000 / 60) % 60),
      seconds: Math.floor((difference / 1000) % 60)
    };
  }

  return timeLeft;
}

function FlatListItem() {
  const [timeLeft, setTimeLeft] = React.useState(calculateTimeLeft());

  React.useEffect(() => {
    const id = setTimeout(() => {
      setTimeLeft(calculateTimeLeft());
    }, 1000);

    return () => {
      clearTimeout(id);
    };
  });

  const timerComponents = Object.keys(timeLeft).map(interval => {
    if (!timeLeft[interval]) {
      return;
    }

    return (
      <span>
        {timeLeft[interval]} {interval}{" "}
      </span>
    );
  });
  1. 我不知道为什么要在您的组件中设置 isLeaving。去掉它。这是没有用的。 clearTimeoutuseEffect.

    的 return 声明中
  2. 使用 StyleSheet.create 中的样式。创建一个函数 keyExtractor 并将其放在您的组件之外。并将项目作为道具传递。

// outside the scope of your component
function keyExtractor(item) {
  return item.id;
}

<FlatList
     style={styles.flatlist} // place your styles in `StyleSheet.create`
     showsVerticalScrollIndicator={false}
     vertical={true}
     data={equipmentData}
     renderItem={EquipmentElement} // pass the item as a prop
     keyExtractor={keyExtractor} 
/>