【问题标题】:Dynamically generated checkbox list performance issues (React)动态生成的复选框列表性能问题 (React)
【发布时间】:2021-12-03 03:04:47
【问题描述】:

我正在开发一个可重复使用的过滤器组件,该组件在下拉列表中动态创建一个复选框列表,并包括一个“全部选中”切换(类似于谷歌航班)。一切都按预期工作,但是单击复选框时会有很大的延迟,尤其是在使用全选切换时。它与here 描述的问题非常相似(甚至几乎相同),但我已尽力实施其中描述的解决方案,但无济于事。我尝试在所有传递的函数上应用 useCallback,并摆脱了“你为什么渲染”的所有警告,但都没有解决问题。我希望这里有人可以帮助告诉我我缺少什么。请参阅下面的相关代码 sn-ps。谢谢!

这是管理数据的父组件:

import React, { useState, useEffect } from "react";
import ControlPanel from '../Components/ControlPanel';

const TopLevelComponent = () => {

    const [data, setData] = useState();
    const [selectedFilters, setSelectedFilters] = useState([]);

    useEffect(() => {
        getData();
    }, [])

    const getData = async() => {
        ...
    }

    return (
        <div>
            <ControlPanel
                filterOptions={ data?.filterSet }
                filterSelections={ selectedFilters }
                filterHandler={ setSelectedFilters }
            />

            { /* other stuff irrelevant here */ }
          
        </div>
    )
}

export default TopLevelComponent;

这是一个可重复使用的控制面板组件,其中包含过滤器和其他设置:

import React from "react";
import { Filter } from './Inputs';

const ControlPanel = ({ filterOptions, filterSelections, filterHandler }) => {

    return (
        <>

            { /* other controls not relevant here */ }

            <div className="control-panel__filters">
                <Filter 
                  filterName="Filter A" 
                  options={ filterOptions } 
                  handler={ filterHandler } 
                  selections={ filterSelections } 
                  selectAllLabel="Select all filter A" 
                />     
            </div>

            { /* more irrelevant stuff */ }

        </>
    )
}

export default ControlPanel;

最后,这是定义过滤器和组成它们的组件的地方:

import React, { useState } from "react";
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem, Label } from 'reactstrap';
import Toggle from 'react-toggle';
import chevronDown from '../icons/chevron-down-dark.svg';
import chevronUp from '../icons/chevron-top.svg';
import closeIcon from '../icons/close.svg';

export const Filter = ({ options, handler, selections, filterName, selectAllLabel }) => {
    
    const [dropdownOpen, setDropdownOpen] = useState(false);

    const toggle = () => setDropdownOpen(prevState => !prevState);
  
    return (
        <Dropdown isOpen={ dropdownOpen } toggle={ toggle } >
            <DropdownToggle>
                { filterName }
                <img src={ dropdownOpen ? chevronUp : chevronDown } />
            </DropdownToggle>
            <DropdownMenu>
                <FilterInterface 
                    toggle={ toggle } 
                    filterName={ filterName } 
                    options={ options } 
                    selections={ selections } 
                    handler={ handler } 
                    selectAllLabel={ selectAllLabel }
                />
            </DropdownMenu>
        </Dropdown>
    );
}

const FilterInterface = ({ toggle, filterName, options, selections, handler, selectAllLabel }) => {

    const [allSelected, setAllSelected] = useState(false);

    const toggleAllSelected = () => {
        if (options.length !== selections.length) {
            const newSelections = options.map(option => option.id);
            handler(newSelections);
            setAllSelected(true);    
        } else {
            handler([]);
            setAllSelected(false);
        }
    }

    const handleCheck = id => {
        let newArray;
        if (selections.includes(id)) {
            newArray = selections.filter(selection => {
                return selection !== id;
            });
            setAllSelected(false);
        } else {
            newArray = [...selections, id];
        }
        handler(newArray);
        if (newArray.length === options.length) setAllSelected(true);
    }

    return (
        <>
            <DropdownItem header>
                { filterName }
                <img src={ closeIcon } onClick={ toggle } />
            </DropdownItem>
            <DropdownItem header>
                {selectAllLabel}
                <Toggle
                    checked={ allSelected }
                    icons={ false }
                    onChange={ toggleAllSelected }
                />
            </DropdownItem>
            {
                options?.map(option => (
                    <DropdownItem header
                        key={ option.id }
                        value={ option.name }
                        className="filterCheckbox"
                    >
                        <Label onClick={ () => handleCheck(option.id) }>
                            <Checkbox checked={ selections.includes(option.id) } readOnly />
                            <span>{ option.name }</span>
                        </Label>
                    </DropdownItem>
                ))
            }
        </>
    )
}

【问题讨论】:

    标签: javascript reactjs performance latency


    【解决方案1】:

    最终似乎实现了链接文章中未讨论的技巧,就是将自定义比较函数传递给记忆化的组件,以便在关闭下拉菜单时它们不会更新。

    【讨论】:

    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-25
    • 1970-01-01
    相关资源
    最近更新 更多