递归查找对象 属性 的路径

Find path of object property, recursively

我想动态打印对象键的路径。这是我的代码:

   const Tree = ({ data }) => {
     let path = "onboarding";
  
      return Object.keys(data).map((key) => {
        if (Array.isArray(data[key])) {
          path = path + "." + key;
          return (
              <Tree data={data[key]}></Tree> 
          );
        }

        if (typeof data[key] === "object") {
          path = path + "." + key;
          return (
              <Tree data={data[key]}></Tree>
          );
        } else {
          path = path + "." + key;    
          return (
            <input defaultValue={data[key]}
              style={{ fontWeight: "bold" }}
              disabled={!this.props.isEditable}/>

          );
        }
      });
    };

及其我的数据

  onboarding: {
    enumType: 1,
    key: "key1",
    steps: [
      {
        title: "STEP ONE",
        description: "des1",
        instructions: [
          {
            icon: "step_power",
            label: {
              text: "text1",
              color: "A11111",
              location: "top",
            },
          },
        ],
      },
      {
        title: "STEP TWO",
        description: "des2",
        instructions: [
          {
            icon: "step_power",
            label: {
              text: "text2",
              color: "A11111",
              location: "top",
            },
          },
       ],
    }

我想为每次迭代打印密钥路径,预期输出:

你必须传递路径作为道具,我做了一个代码框:https://codesandbox.io/s/old-browser-crgd9r

编辑:根据评论建议在此处添加相关代码

const Tree = ({ path, data }) => {
  // We have 3 cases: Array, Object or neither
  // If we have an array we want to cycle through the elements
  // and keep track of the index
  // If we have an object we want to cicle through the keys
  // otherwise just return the value

  if (Array.isArray(data)) {
    return data.map((element, index) => {
      let currentPath = `${path}[${index}]`;
      return (
        <Tree
          path={currentPath}
          data={element}
          key={currentPath}
        ></Tree>
      );
    });
  } else if (data instanceof Object) {
    return Object.keys(data).map((key) => {
      let currentPath = path !== "" ? `${path}.${key}` : key;
      return <Tree data={data[key]} path={currentPath} key={currentPath} />;
    });
  } else {
    return (
      <div>
        <label>{path}</label>
        <input defaultValue={data} style={{ fontWeight: "bold" }} />
      </div>
    );
  }
};

另一种方法是将 path-extraction 代码与 DOM-generation 部分分开。这将使您能够使用更多可重用的函数。

下面是我可能会用两种不同的方式来写 path-extraction 的文章。首先作为输出格式的 all-in 一个函数:

const stringPaths = (o, p = '') =>
  Array .isArray (o) 
    ? o .flatMap ((v, i) => [p, ...stringPaths (v, `${p}[${i}]`)]) .filter (Boolean)
  : Object (o) === o
    ? [
        p, 
        ... Object .entries (o) .flatMap (([k, v]) => stringPaths (v, p ? `${p}.${k}` : k))
      ] .filter (Boolean)
  : p


const onboarding = {enumType: 1, key: "key1", steps: [{title: "STEP ONE", description: "des1", instructions: [{icon: "step_power", label: {text: "text1", color: "A11111", location: "top"}}]}, {title: "STEP TWO", description: "des2", instructions: [{icon: "step_power", label: {text: "text2", color: "A11111", location: "top"}}]}]}
 
console .log (stringPaths (onboarding))
.as-console-wrapper {max-height: 100% !important; top: 0}

其次,以我喜欢的方式,生成一种更广泛使用的中间格式([["enumType"], ["key"], ["steps"], ["steps", 0], ["steps", 0, "title"], ..., ["steps", 1, "instructions", 0, "label", "location"]],然后将其转换为您的目标格式:

const getPaths = (o) => Object (o) === o
  ? Object .entries (o) 
      .flatMap (([k, v], _, __, k1 = Array .isArray (o) ? Number (k) : k) => 
        [[k1], ...getPaths (v) .map (p => [k1, ...p])]
      )
  : []

const stringPaths = (o) => 
  getPaths (o) .map (
    (path) => path .reduce ((p, n, i) => i == 0 ? n : Number .isInteger (n) ? `${p}[${n}]` : `${p}.${n}`, ``)
  )

const onboarding = {enumType: 1, key: "key1", steps: [{title: "STEP ONE", description: "des1", instructions: [{icon: "step_power", label: {text: "text1", color: "A11111", location: "top"}}]}, {title: "STEP TWO", description: "des2", instructions: [{icon: "step_power", label: {text: "text2", color: "A11111", location: "top"}}]}]}
 
console .log (stringPaths (onboarding))
.as-console-wrapper {max-height: 100% !important; top: 0}

我认为这种细分有助于更好地编写代码。