【问题标题】:How to prevent unnecessary renders when checking a checkbox?选中复选框时如何防止不必要的渲染?
【发布时间】:2021-06-24 23:56:48
【问题描述】:

我正在尝试创建高性能的复选框树组件。我有一个父级状态来保存选中复选框 ID 的列表 =>

const [selected, setSelected] = useState([]);

当切换复选框时,它的 ID 会添加到该数组或从该数组中删除。我将布尔值传递给控制选中状态的每个复选框 =>

checked={selected.includes(hole.id)}

Checkbox -input 被分离到一个自己的 CheckboxNode 组件中。

当不为 CheckboxNode 组件使用React.memo 时,我总是可以看到来自同一个父级的每个复选框触发console.log(),即使只有一个被单击/切换

当使用 React.memo 并进行以下检查时,我在切换复选框时看到 1-3 个渲染 =>

const areEqual = (prev, next) => prev.checked === next.checked;

此外,视觉状态的变化非常特别,组件感觉非常有问题。

如何在这样的设置中获得出色的性能并摆脱额外的渲染?我在这里添加了代码,以便任何人都可以更好地查看:https://codesandbox.io/s/shy-frog-4wjrg?file=/src/CheckboxNode.js

【问题讨论】:

    标签: javascript reactjs checkbox react-hooks


    【解决方案1】:

    一个带有useCallback 的记忆函数,如果你引用一个给定的状态,它会导致错误的行为。

    发生这种情况是因为您将保留该状态的陈旧引用。 一个解决方案是使用回调函数调用任何setState。回调将始终传递当前状态引用,从而导致预期的行为。

      const handleToggleParent = useCallback(
        (site) => {
          // if you pass a function to setSelected, selected will be always be the correct reference
          setSelected((selected) => {
            let copyOfOriginal = [...selected];
            const parentChecked = copyOfOriginal.includes(site.id);
    
            if (parentChecked) {
              // Uncheck parent
              copyOfOriginal = copyOfOriginal.filter((id) => id !== site.id);
            } else {
              // Check parent
              copyOfOriginal.push(site.id);
            }
    
            for (const hole of site.Holes) {
              if (parentChecked) {
                // Uncheck all childs
                copyOfOriginal = copyOfOriginal.filter((id) => id !== hole.id);
              } else {
                // Check all childs
                copyOfOriginal.push(hole.id);
              }
            }
    
            return copyOfOriginal;
          });
        },
        [setSelected]
      );
    
      const handleToggleChild = useCallback(
        (hole, site) => {
          // if you pass a function to setSelected, selected will be always be the correct reference
          setSelected((selected) => {
            let copyOfOriginal = [...selected];
    
            if (copyOfOriginal.includes(hole.id)) {
              copyOfOriginal = copyOfOriginal.filter((id) => id !== hole.id);
    
              // also remove parent checked when any child is not checked
              copyOfOriginal = copyOfOriginal.filter((id) => id !== site.id);
            } else {
              copyOfOriginal.push(hole.id);
    
              // also check parent if all child holes are checked
              if (site) {
                if (site.Holes.every((hole) => copyOfOriginal.includes(hole.id))) {
                  copyOfOriginal.push(site.id);
                }
              }
            }
    
            return copyOfOriginal;
          });
        },
        [setSelected]
      );
    

    【讨论】:

    • 哇,这对我来说是很棒的信息!谢谢你,工作就像一个魅力?
    猜你喜欢
    • 2021-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-02
    • 2019-04-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多