【问题标题】:Count array item every time condition is met with useEffect每次使用 useEffect 满足条件时对数组项进行计数
【发布时间】:2023-01-26 04:54:26
【问题描述】:

每次在每个 array.push 中满足此条件时,我都会尝试设置一个计数器:

    interface FilterProps {
            filterQuery: any
            setFilterQuery: (e: any) => any
            resetFilter: (e: any) => any
            handleCategory: (e: any) => any
            categoryList: any
            getCategoryValue: any
            handleOnClick: (e: any) => any
            paginateOnClick: (e: any) => any
            paginateIcon: any
            handleToggle: (e: any) => any
            checkState: any
            expandFilter: boolean
            printEvent: PrintEvent
        }
        
        export const EventFilter: React.FC<FilterProps> = ({
            filterQuery,
            setFilterQuery,
            resetFilter,
            handleCategory,
            categoryList,
            getCategoryValue,
            handleOnClick,
            paginateOnClick,
            paginateIcon,
            handleToggle,
            checkState,
            expandFilter,
        }, printEvent: PrintEvent) => {
        
        
             const [countUnlabeled, setCountUnlabeled] = React.useState(0)
            
                const classes = useStyles()
            
                const { box, ui } = useStores()
            
                const { labels } = printEvent
            
                let unlabeledEvents: any[] = []
            
                function getUnlabeled() {
                    box.descEvents.forEach((printEvent: PrintEvent) => {
            
            
         
            
                        const isStopEvent =
                            (printEvent && printEvent.name === 'control_fault') ||
                            (printEvent.name === 'running' && printEvent.value === false) ||
                            (printEvent.name === 'safety_chain' && printEvent.value === false) ||
                            (printEvent.name === 'torch_collision' && printEvent.value === true) ||
                            (printEvent.name === 'motion_sup' && printEvent.value === true) ||
                            (printEvent.name === 'e_stop' && printEvent.value === true)
            
                        const unlabeled = printEvent.labels === null && isStopEvent
            
            
                        if (unlabeled) {
                            unlabeledEvents.push(unlabeled)
                            ui.setUnlabeledCount(unlabeledEvents.length)
                        }
            
                    })
                }
    
    
        useEffect(() => {
            if (box.descEvents && printEvent) {
                getUnlabeled()
                console.log('useEffect just ran', ui.unlabeledCount, unlabeledEvents.length)
            }
        }, [unlabeledEvents, ui.unlabeledCount, printEvent.name])
    
        return (
            <Accordion
                className={classes.eventAccordion}
                TransitionProps={{ unmountOnExit: true }}
                defaultExpanded={expandFilter}
            >
                <AccordionSummary>
                    <div className={classes.filterHeader}>
                        <div className={classes.filterText}>
                            <FilterListIcon />
                            <p>Filter by:</p>
                        </div>
                        <div className={classes.unfiltered}>
                            Unlabeled events: &nbsp;
                            <Chip
                                size="small"
                                label={ui.unlabeledCount}
                                className={classes.chipMissing}
                            />
    
                        </div>
    
                    </div>
                </AccordionSummary>
    </Accordion>

export default EventFilter

通常它应该在每次推送事件或数组发生变化时运行功能检查,但它不会同步计数。 我尝试向未标记的条件添加一个计数,但没有用,不想让这里的事情过于复杂。

这里有什么问题?

counter example

【问题讨论】:

  • 效果在渲染后运行。设置状态会导致渲染。您在循环中有一个 setState 调用(或看起来像一个调用)。设置状态是异步和批处理的。你到底想做什么?
  • 基本上是在每次满足未标记条件时增加计数器(未标记事件)。

标签: javascript reactjs for-loop react-hooks count


【解决方案1】:

在 React 中,您在功能组件主体中编写的内容会在每次渲染时运行。这意味着

let unlabeledEvents: any[] = [];
useEffect(() => {
    console.log(unlabeledEvents);
}, [unlabeledEvents]);

每次渲染组件时都会创建一个新数组,保持对象引用(或长度,或任何其他属性)不变。如果您想对对象的更改做出反应,您需要一种方法将旧引用存储在某处,然后以创建新引用的方式更新它。这正是 useState 钩子的用途。只需确保每次都创建一个新数组以更新该引用:

const [unlabeledEvents, setUnlabeledEvents] = useState<any[]>([]);

function getUnlabeled() {
     // find unlabeled item
     if (unlabeled) {
          setUnlabeledEvents([...unlabeledEvents, unlabeled]);
     }
}

这样,每次getUnlabeledunlabeledEvents 数组添加一个新条目时,您的useEffect 就会运行。您也可以放弃 countUnlabeled,因为 unlabeledEvents 将始终是最新的,您可以直接使用它的长度。

但是,您确定您的 useStores 钩子按预期工作吗?由于我们对此一无所知,因此它可能会遇到与上述相同的问题。如果是这样,我建议改用useMemo,以便在每次更改box 时重新计算数组(因为无论如何都要迭代整个数组):

const { box } = useStores();

const unlabeledEvents = useMemo(
    box.descEvents.filter((e) => true /* your unlabeled condition here */)
    [box]
)

另请查看this question,了解有关更新组件中有状态数组的更多详细信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-13
    • 2017-06-23
    • 1970-01-01
    • 2017-09-15
    • 1970-01-01
    相关资源
    最近更新 更多