react-native-skeleton-placeholder icon indicating copy to clipboard operation
react-native-skeleton-placeholder copied to clipboard

SkeletonPlaceholder.Item not rendered if wrapped in another component

Open canpoyrazoglu opened this issue 2 years ago • 1 comments

In my SkeletonPlaceholder if I use SkeletonPlaceholder.Item anywhere its fine. Here is how it works:

<SkeletonPlaceholder.Item width={40} height={16} />

I want to wrap it in a commonly used way so I created this to skip rewriting props each time (and to be able to manage):


type TextPlaceholderProps = {
  width?: number;
};
function TextPlaceholder(props: TextPlaceholderProps) {
  const width = props.width ?? 40;

  return <SkeletonPlaceholder.Item height={16} width={width} />;
}

However, that doesn't render even though it's the exact same component.

canpoyrazoglu avatar Sep 14 '23 22:09 canpoyrazoglu

Also running into this problem. I came up with a sort of workaround. Not super happy with this, but it seems to work.

Instead of creating reusable components, create reusable markup functions.

Example:

// SkeletonMarkup.tsx

export type SkeletonMarkupFunction<T extends object = {}> = (
  options: {
    theme: Theme;
    props?: React.ComponentProps<typeof SkeletonPlaceholder.Item>;
  } & T,
) => JSX.Element;

export const SkeletonMarkup: Record<string, SkeletonMarkupFunction<any>> = {
  text(options) {
    return (
      <SkeletonPlaceholder.Item
        height={options.theme.textVariants.body.lineHeight}
        width={100}
        {...options.props}
      />
    );
  },
  // Other "globally" reusable skeleton components go here
};

// Avatar.tsx

export const Avatar = () => { <>...</> }

const skeletonMarkup: SkeletonMarkupFunction<{size: AvatarSize}> = ({
  props,
  size
}) => {
  const resolvedSize = AVATAR_SIZES[size];

  return <SkeletonPlaceholder.Item
    {...props}
    width={resolvedSize}
    height={resolvedSize}
    borderRadius={resolvedSize / 2}
  />
}
Avatar.skeletonMarkup = skeletonMarkup;

// Header.tsx – a component I want a complex skeleton for

export const Header = () => { <>...</> }

const skeletonMarkup: SkeletonMarkupFunction = ({theme, props}) => {
  return <SkeletonPlaceholder.Item 
    {...props}>
    {SkeletonMarkup.text({theme, props: {marginButton: 12}})}
    {SkeletonMarkup.text({theme, props: {marginButton: 12}})}
    {Avatar.skeletonMarkup({theme, size: 'sm'})}
  </SkeletonPlaceholder.Item>
}
Header.skeletonMarkup = skeletonMarkup;

// Screen.tsx

const Screen = () => {
  const theme = useTheme();
  
  if(loading) {
    return <SkeletonPlaceholder>
      {Header.skeletonMarkup({theme, marginButton: 12})}
      <SkeletonPlaceholder.Item height={300} width={300} />
    </SkeletonPlaceholder/>
  }

  ...
}

matthewtory avatar Feb 23 '24 17:02 matthewtory