react-native-skeleton-placeholder
react-native-skeleton-placeholder copied to clipboard
SkeletonPlaceholder.Item not rendered if wrapped in another component
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.
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/>
}
...
}