1

I need a way to give the users of my React Web application the ability to deep-link to individual components (marked with a deeplinkKey prop) on any page. A user would go to a URL which includes a component key. The app would then make visible the component(s) where the deeplinkKey prop matches the given key only, hiding all other elements with deeplinkKey props. (Elements without a deeplinkKey prop would always show.)

I currently have a wrapper component that shows/hides elements within its child tree based on a whitelist (included below). However, the wrapper element can't see unrendered children.

How can I enable the user to link to hidden elements like 'resourceA' in this example and have <DeeplinkWrapper> render them:

let condition = true;

<DeeplinkWrapper deeplinkWhitelist=['resourceA']>
  <Root>
    {condition ? 
      <ParentElement1>
        <Element deeplinkKey='someResource' />
      </ParentElement1>
      :
      <ParentElement2>
        <Element deeplinkKey='resourceA' />
      </ParentElement2>
    }
  </Root>
</DeeplinkWrapper>

/*
Desired "deep-linked" render:

<Root>
  <ParentElement2>
    <Element deeplinkKey='resourceA' />
  </ParentElement2>
</Root>
*/

Here is my wrapper. It operates based on these rules:

// Any child element of <DeeplinkWrapper> will show if:
//  The whitelist array is empty
//  The child is pure text or null
//  The child does not have the 'deeplinkKey' prop
//  The child's 'deeplinkKey' prop exists and its value is in the whitelist array 

// Any child element of <DeeplinkWrapper> will be hidden if:
//  It's a child of a hidden parent
//  The child's 'deeplinkKey' prop exists, but is not in the whitelist
//  The child's 'deeplinkKey' prop exists, but is undefined, e.g. <span deeplinkKey>Text</span>
export default function DeeplinkWrapper({ children, whitelist = [] }) {
  const showWhitelistedComponents = (children, fn) => {
    return React.Children.map(children, child => {
      const isReactElement = React.isValidElement(child);
      const doShow = !isReactElement || !child.props.deeplinkKey || whitelist.indexOf(child.props.deeplinkKey) !== -1;

      if (!isReactElement) {
        return doShow ? child : null;
      }

      if (child.props.children) {
        child = React.cloneElement(child, {
          children: showWhitelistedComponents(child.props.children, fn)
        });
      }

      return doShow ? fn(child) : null;
    });
  }

  return (
    <React.Fragment>
      {whitelist.length === 0 ? React.Children.map(children, child => child) : showWhitelistedComponents(children, child => child)}
    </React.Fragment>
  )
}
Paul
  • 402
  • 4
  • 12

0 Answers0