LoginSignup
0
0

More than 1 year has passed since last update.

【React Native】コールバック化したchildrenにパラメータを渡す

Last updated at Posted at 2022-04-19

はじめに

シャドウのスタイルをつけたコンポーネントでバナー画像をラップすると、そのままでは高さが設定されず、上下に余計なマージンが入ってしまう感じになってしまいました。

その解決策として、シャドウのコンポーネントで高さ(height)を設定した後に、コールバック化したchildrenにheightをパラメータとして渡してあげるようにしました。

childrenにパラメータを渡す方法をお探しの方には参考となる内容だと思います。

実装

いらすとやからとってきたバナー画像に、以下のようなシャドウをつけます。

まず、シャドウのスタイルをつけるコンポーネントShadowStyledViewを作成します。
onLayoutViewの widthを取得し、このwidthにアスペクト比をかけてheightを算出します。
そして、childrenfunctionのときの場合のみ、widthheightを渡してあげるようにします。

また、imageWidthimageHeightをpropsに置くことで、アスペクト比を可変させることもできます。

ShadowStyledView.tsx
type ResizedProps = {
  width: number;
  height: number;
};

type ShadowStyledViewProps = {
  containerStyle?: StyleProp<ViewStyle>;
  imageWidth?: number;
  imageHeight?: number;
  children: ReactNode | ((resizedProps: ResizedProps) => ReactNode);
};

export const ShadowStyledView: React.FC<ShadowStyledViewProps> = React.memo(
  ({ containerStyle, imageWidth = 800, imageHeight = 287, children }) => {
    const { onLayout, width } = useLayout();
    const height = (width * imageHeight) / imageWidth;

    return (
      <View onLayout={onLayout} style={[styles.container, containerStyle]}>
        {typeof children === "function" ? children({ width, height }) : children}
      </View>
    );
  },
);

ShadowStyledView.displayName = "ShadowStyledView";

const styles = StyleSheet.create({
  container: {
    ...Platform.select({
      ios: {
        shadowColor: "rgba(0,0,0,0.15)",
        shadowOffset: { width: 0, height: 5 },
        shadowRadius: 1,
        shadowOpacity: 1,
      },
      android: { elevation: 5 },
    }),
  },
});

なお、onLayoutwidthについては、カスタムフックuseLayout() にまとめます。

useLayout.ts
export function useLayout() {
  const [layout, setLayout] = useState({
    x: 0,
    y: 0,
    width: 0,
    height: 0,
  });

  const onLayout = useCallback(
    ({ nativeEvent }: LayoutChangeEvent) => setLayout(nativeEvent.layout),
    [],
  );

  return {
    onLayout,
    ...layout,
  };
}

バナーのコンポーネントQuestionBannerは以下のようになります。
ShadowStyledViewの中身でImageをコールバックで呼び、heightをパラメータとして渡しています。
これで指定したアスペクト比でシャドウをつけたバナーを表示させることができます。

QuestionBanner.tsx
type QuestionBannerProps = {
  containerStyle?: StyleProp<ViewStyle>;
  children?: never;
};

export const QuestionBanner: React.FC<QuestionBannerProps> = React.memo(({ containerStyle }) => {
  return (
    <ShadowStyledView containerStyle={[containerStyle]}>
      {({ height }) => (
        <Image
          source={QuestionBannerImage}
          style={{
            height,
            resizeMode: "contain",
            borderRadius: 5,
            width: "100%",
          }}
        />
      )}
    </ShadowStyledView>
  );
});

QuestionBanner.displayName = "QuestionBanner";

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0