Quiero imprimir la ruta de la clave del objeto, dinámicamente. Aquí está mi código:
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}/> ); } }); };y son mis datos
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", }, }, ], }Y quiero imprimir la ruta de la clave para cada iteración, salida esperada:
Tienes que pasar la ruta como accesorio, hice un cuadro de código: https://codesandbox.io/s/old-browser-crgd9r
Editar: agregando código relevante aquí como comentario sugerido
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> ); } };Otro enfoque sería separar el código de extracción de ruta de la parte de generación de DOM. Esto le permitiría trabajar con más funciones reutilizables.
Así es como podría escribir la pieza de extracción de ruta, de dos maneras diferentes. Primero como una función todo en uno para su formato de salida:
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} Y luego, en segundo lugar, en mi estilo preferido, generando un formato intermedio más útil ( [["enumType"], ["key"], ["steps"], ["steps", 0], ["steps", 0, "title"], ..., ["steps", 1, "instructions", 0, "label", "location"]] , y luego convertirlo en su formato de destino:
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}Creo que este desglose hace que la codificación sea mucho más agradable.