Wednesday, March 15, 2023

safely walking down a tree structure via reduce

 At work we have theme files, so you might have a button or something that will look for its color, say in something like this: 

theme["button"]["large"]["primary"]["backgroundColor"]; 

so if you codify that as 

theme[componentName][size][type].backgroundColor 

it might blow up if part is missing... so you can defensively code it like 

theme?.[componentName]?.[size]?.[type]?.backgroundColor

But I wanted to print out more diagnostic information, not just safely null out... here's the content of the  codepen I came up with, which lets you call something like

getRootNode(theme,componentName,size,type,backgroundColor);

Here's the codepen code:

const getRootNode = (theme,...keys) => {
    const foundNode = keys.reduce(
      (node, key)=>{
        return node ? node[key] : null;
      }, theme);
    if(! foundNode) {
      console.log(`Could not find rootNode for ${keys}`);
      console.log(theme);
    }
    return foundNode;
}

const tree = {
  apple:{
    red:{},
    green:
      { taste: 'tart'}
  },
  banana:{
  },
  pear:{
    
  }
};
console.log('got');
console.log(getRootNode(tree,'apple','green', 'taste'));

It walks down the theme tree, but if there's no content anywhere along the line it calmly complains and returns null.

FOLLOWUP: I'm having some trouble selling my coworkers on this, they like the elegance/transparency of the chain syntax vs an arbitrary helper function. They also questioned the efficiency, so I wrote up a stopwatch function:

console.time();
for (let i = 0; i < 100000; i++) {
  const foo = getNodeInTheme(props.theme,"Badge",props.variant,props.size,props.color);
}
console.timeEnd();
console.time();
for (let i = 0; i < 100000; i++) {
  const bar = props.theme.Badge![props.variant!][props.size!][props.color!]
}
console.timeEnd();

Results: 

default: 18.383056640625 ms default: 1.559814453125 ms

And yeah, technically it's like 10 times slower, but 10,000 calls is still only 20 milliseconds, which is 0.02 seconds.  And that's for a LOT of calls.

Heh. Reminds me of BASIC that lacked a "SLEEP" command so you'd write "do-nothing" FOR...NEXT loops. And they weren't superfast!




No comments:

Post a Comment