react-native-skeleton-placeholder
react-native-skeleton-placeholder copied to clipboard
Extract Skeleton Items to another component then reuse it?
I have a component called Loader.tsx
import React from "react";
import SkeletonPlaceholder from "react-native-skeleton-placeholder";
type LoaderProps = {
children: JSX.Element | JSX.Element[];
};
export default function Loader(props: LoaderProps) {
const { children } = props;
return (
<SkeletonPlaceholder highlightColor="#333333" backgroundColor="#121212">
{children}
</SkeletonPlaceholder>
);
}
Now I create a component contains Skeleton items
const VideoCardLoader = () => {
return (
<SkeletonPlaceholder.Item
width={CardWidth}
marginRight={CardPaddingRight}
marginBottom={CardPaddingBottom}
>
<SkeletonPlaceholder.Item
width={CardWidth}
height={ImageHeight * ImageRatio}
marginBottom={5}
/>
<SkeletonPlaceholder.Item
height={TitleFontSize}
width={CardWidth * 0.7}
marginBottom={5}
/>
<SkeletonPlaceholder.Item
height={StudiosFontSize}
width={CardWidth * 0.4}
/>
</SkeletonPlaceholder.Item>
);
};
Now when I try to use it in HomeScreen, I would write
export default function HomeScreen() {
const { data, isLoading, isError } = useHomePage();
if (isLoading) {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Loader>
<VideoCardLoader />
</Loader>
</View>
);
}
return <Text>Loaded....</Text>
}
Sadly this way didn't works as I expected. This should works but somehow it didn't...
Edit: After minutes of trying, I found out this way works as I expected. But the syntax looks not that good.
import React from 'react';
import { SafeAreaView, Dimensions } from 'react-native';
import SkeletonPlaceholder from 'react-native-skeleton-placeholder';
const { width: windowWidth } = Dimensions.get('window');
const Loader = ({ loader: Loader }) => (
<SkeletonPlaceholder>{Loader}</SkeletonPlaceholder>
);
const AvatarLoader = (
<SkeletonPlaceholder.Item flexDirection="row" alignItems="center">
<SkeletonPlaceholder.Item width={60} height={60} borderRadius={50} />
<SkeletonPlaceholder.Item marginLeft={20}>
<SkeletonPlaceholder.Item width={120} height={20} borderRadius={4} />
<SkeletonPlaceholder.Item
marginTop={6}
width={80}
height={20}
borderRadius={4}
/>
</SkeletonPlaceholder.Item>
</SkeletonPlaceholder.Item>
);
const PostLoader = (
<>
{AvatarLoader}
<SkeletonPlaceholder.Item width={windowWidth} height={300} marginTop={10} />
</>
);
const App = () => {
return (
<SafeAreaView>
<Loader loader={PostLoader} />
</SafeAreaView>
);
};
export default App;
hmmm, good catch I'll try to do something to make it work
hmmm, good catch I'll try to do something to make it work
After looking at your source code, I figured out why it didn't work. So I tried this approach, take a look at it to see if it helps.
const getChildren = React.useCallback(
(element: JSX.Element | JSX.Element[]) => {
return React.Children.map(element, (child: JSX.Element, index: number) => {
// If the component neither SkeletonItem nor View.
// Then assume it is a custom component that using SkeletonPlaceholder
// just return it directly.
if (
child.type.displayName !== "SkeletonPlaceholderItem" ||
child.type.displayName !== "View"
) {
return child;
}
let style: ViewStyle;
if (child.type.displayName === "SkeletonPlaceholderItem") {
const { children, ...styles } = child.props;
style = styles;
} else {
style = child.props.style;
}
if (child.props.children) {
return (
<View key={index} style={style}>
{getChildren(child.props.children)}
</View>
);
} else {
return (
<View key={index} style={styles.childContainer}>
<View style={[style, viewStyle]} />
</View>
);
}
});
},
[viewStyle]
);
is this issue solved? im trying to make my component reusable