【问题标题】:How to efficiently change value for a certain key in object that has recursion in JS/TS如何有效地更改在 JS/TS 中具有递归的对象中某个键的值
【发布时间】:2021-08-07 07:01:09
【问题描述】:

我有一个接受以下数据结构的树组件

type TreeNode = {
  id: string,
  parentId: string,
  renderer: () => React.ReactNode,
  expanded: boolean,
  children?: Array<TreeNode>,
}

我想实现Expand All / Collapse All 功能,从技术上讲,该功能将针对该树的所有TreeNode 将expanded 更改为true/false

当我有label: string而不是renderer: function时,我使用了以下方法,这似乎是完美的。

function updateAllNodes(rootNode, newExpanded) {
    return JSON.parse(
        JSON.stringify(rootNode)
            .replaceAll(
                `"expanded": ${!newExpanded}`, 
                `"expanded": ${newExpanded}`
            )
    );
}

但只要我们有节点的渲染器函数,我就不能再使用这种方法了。

什么是最好的解决方案?

【问题讨论】:

  • 为什么不用循环功能?
  • 你的反应函数有什么问题?
  • JSON.parse(JSON.stringify()) 将删除所有函数
  • 绝对不要在 JSON 上使用字符串替换来更新你的数据!!!

标签: javascript reactjs typescript object recursion


【解决方案1】:

假设我们有mytree -

const mytree =
  { id: 1, active: false, children: [
      { id: 11, active: true, children: [
          { id: 111, active: false },
          { id: 112, active: true }
        ]
      },
      { id: 12, active: false },
      { id: 13, active: true, children: [
          { id: 131, active: false }
        ]
      }
    ]
  }

您可以不可变地更新使用递归函数recUpdate -

const recUpdate = (t, f) =>
  ({ ...t, children: t?.children?.map(c => recUpdate(c, f)), ...f(t) })

我们的高阶函数可以专门写成activatedeactivate——

const activate = t =>
  recUpdate(t, _ => ({ active: true }))

const deactivate = t =>
  recUpdate(t, _ => ({ active: false }))

调用activate 将生成一棵新树,其中所有active = true -

console.log(activate(mytree))
{ id: 1, active: true, children: [
    { id: 11, active: true, children: [
        { id: 111, active: true },
        { id: 112, active: true }
      ]
    },
    { id: 12, active: true },
    { id: 13, active: true, children: [
        { id: 131, active: true }
      ]
    }
  ]
}

调用deactivate 将生成一棵新树,其中所有active = false -

console.log(deactivate(mytree))
{ id: 1, active: false, children: [
    { id: 11, active: false, children: [
        { id: 111, active: false },
        { id: 112, active: false }
      ]
    },
    { id: 12, active: false },
    { id: 13, active: false, children: [
        { id: 131, active: false }
      ]
    }
  ]
}

mytree 没有变异 -

console.log(mytree)
{ id: 1, active: false, children: [
    { id: 11, active: true, children: [
        { id: 111, active: false },
        { id: 112, active: true }
      ]
    },
    { id: 12, active: false },
    { id: 13, active: true, children: [
        { id: 131, active: false }
      ]
    }
  ]
}

展开下面的sn-p,在浏览器中验证结果-

const recUpdate = (t, f) =>
  ({ ...t, children: t?.children?.map(c => recUpdate(c, f)), ...f(t) })

const activate = t =>
  recUpdate(t, _ => ({ active: true }))

const deactivate = t =>
  recUpdate(t, _ => ({ active: false }))

const mytree =
  { id: 1, active: false, children: [
      { id: 11, active: true, children: [
          { id: 111, active: false },
          { id: 112, active: true }
        ]
      },
      { id: 12, active: false },
      { id: 13, active: true, children: [
          { id: 131, active: false }
        ]
      }
    ]
  }

console.log(JSON.stringify(activate(mytree)))
console.log(JSON.stringify(deactivate(mytree)))
console.log(JSON.stringify(mytree))

【讨论】:

    猜你喜欢
    • 2020-12-01
    • 2020-07-06
    • 1970-01-01
    • 2020-12-14
    • 1970-01-01
    • 2020-02-26
    • 1970-01-01
    • 1970-01-01
    • 2014-08-10
    相关资源
    最近更新 更多