Как я могу "диплинк" реагировать на веб-компоненты, даже если они скрыты? - PullRequest
1 голос
/ 24 февраля 2020

Мне нужен способ дать пользователям моего веб-приложения React возможность делать глубокие ссылки на отдельные компоненты (помеченные deeplinkKey prop) на любой странице. Пользователь будет go на URL, который включает в себя ключ компонента. Затем приложение сделает видимым компонент (ы), в которых deeplinkKey prop соответствует данному ключу only , скрывая все остальные элементы с deeplinkKey реквизитом. (Элементы без deeplinkKey prop всегда показывались бы.)

В настоящее время у меня есть компонент-обертка, который показывает / скрывает элементы в своем дочернем дереве на основе белого списка (включен ниже). Однако элемент-обертка не может видеть неопределяемые дочерние элементы.

Как разрешить пользователю ссылаться на скрытые элементы, такие как 'resourceA' в этом примере, и <DeeplinkWrapper> отображать их:

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>
*/

Вот моя обертка. Он работает на основе этих правил:

// 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>
  )
}
...