🛎️

【React】react-horizontal-scrolling-menuのライブラリを使って横スクロール

2022/07/09に公開

概要

Reactで横スクロールを実装する際に、何か良いライブラリないかなと探してみたところ、asmyshlyaev177/react-horizontal-scrolling-menuというのが良さげな感じがありました。
少し試してみましたので紹介します。

題材

以下のようなイメージで、横スクロールで日付を選択できる表示を実装します。

実装サンプル

サンプルでは、ReactNativeのコンポーネントをベースとしていますが、普通のReactでも同様の実装でいけるかなと思います。

以下がreact-horizontal-scrolling-menuの使用した箇所です。

import { useContext } from "react";
import { StyleSheet, View, TouchableOpacity } from "react-native";
import { ScrollMenu, VisibilityContext } from "react-horizontal-scrolling-menu";
import Icon from "react-native-vector-icons/FontAwesome";
import {
  dateDisplayFormattedStr,
  dateKeyFormattedStr,
} from "../../../util/DateUtil";
import SampleDateComponent from "./SampleDateComponent";

export default function SampleDatesSelectComponent() {
  let sampleDates = [];

  // 表示する日付の設定部分
  for (let i = 0; i < 14; i++) {
    const targetDate = new Date();
    if (i > 0) {
      targetDate.setDate(targetDate.getDate() + i);
    }
    // 日付のフォーマット部分(メソッドのロジックについての記載は割愛)
    sampleDates.push({
      key: dateKeyFormattedStr(targetDate),
      label: dateDisplayFormattedStr(targetDate),
    });
  }

  const Arrow = ({ children, onClick, style }) => {
    return (
      <>
        <TouchableOpacity onPress={onClick} style={style}>
          {children}
        </TouchableOpacity>
      </>
    );
  };

  const LeftArrow = () => {
    const { isFirstItemVisible, scrollPrev } = useContext(VisibilityContext);
    return (
      <Arrow onClick={() => scrollPrev()} style={styles.leftArrow}>
        <Icon
          name="angle-left"
          size={40}
          color={isFirstItemVisible ? "white" : "black"}
        />
      </Arrow>
    );
  };

  const RightArrow = () => {
    const { isLastItemVisible, scrollNext } = useContext(VisibilityContext);
    return (
      <Arrow onClick={() => scrollNext()} style={styles.rightArrow}>
        <Icon
          name="angle-right"
          size={40}
          color={isLastItemVisible ? "white" : "black"}
        />
      </Arrow>
    );
  };

  return (
    <View style={styles.container}>
      <View style={styles.menu}>
        <ScrollMenu LeftArrow={LeftArrow} RightArrow={RightArrow}>
          {sampleDates.map((d) => (
            <SampleDateComponent
              itemId={d.key}
              dateKey={d.key}
              dateLabel={d.label}
            />
          ))}
        </ScrollMenu>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    alignItems: "center",
  },
  menu: {
    width: "70%",
  },
  rightArrow: {
    marginLeft: "15px",
  },
  leftArrow: {
    marginRight: "15px",
  },
});

おまけで日付を選択するコンポーネントは以下です。

import { useContext } from "react";
import { StyleSheet, TouchableOpacity, Text, View } from "react-native";
import { SampleContext } from "../../../context/SampleProvider";

export default function SampleDateComponent(prop) {
  const { sampleDate, setSampleDate } = useContext(SampleContext);

  const onPress = () => {
    setSampleDate(prop.dateKey);
  };

  return (
    <TouchableOpacity onPress={onPress}>
      <View
        style={
          prop.dateKey === sampleDate
            ? styles.buttonSelected
            : styles.buttonNotSelected
        }
      >
        <Text>{prop.dateLabel}</Text>
      </View>
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  buttonNotSelected: {
    borderRadius: 8,
    paddingVertical: 10,
    paddingHorizontal: 10,
    backgroundColor: "#f8f8ff",
    marginRight: "5px",
    paddingBottom: "20px",
  },
  buttonSelected: {
    borderRadius: 8,
    paddingVertical: 10,
    paddingHorizontal: 10,
    backgroundColor: "#dcdcdc",
    marginRight: "5px",
    paddingBottom: "20px",
  },
});

Discussion