Yamada UIにスターをあげる

スター
Yamada UIYamada UIv1.7.2

InfiniteScrollArea

InfiniteScrollAreaは、無限スクロール機能を提供するコンポーネントです。このコンポーネントは、コンポーネントの終わりに達したときに次のデータセットを自動的に読み込み、表示することで、スムーズなスクロール体験を提供します。

ソース@yamada-ui/infinite-scroll-area

インポート

import { InfiniteScrollArea } from "@yamada-ui/react"
Copied!

使い方

編集可能な例

const [count, setCount] = useState<number>(50)

return (
  <InfiniteScrollArea
    onLoad={({ index, finish }) => {
      console.log("load", index)

      setCount((prev) => prev + 50)

      if (index >= 5) finish()
    }}
    loading={<Loading fontSize="2xl" />}
  >
    <For each={Array.from({ length: count })}>
      {(_, index) => (
        <Card key={index}>
          <CardHeader>
            <Heading size="md">俺を誰だと思っていやがるッ!!</Heading>
          </CardHeader>

          <CardBody>
            <Text>
              『天元突破グレンラガン』は、ガイナックス・アニプレックス・コナミデジタルエンタテインメント製作の日本のロボットアニメ作品。
            </Text>

            <Text>
              作品名の「天元」とは、万物生育の根源という意味があり、また囲碁の用語では碁盤の中央(中心)を指す。劇中のキーワードにも螺旋、ドリル、回転など、中央・中心に関連するものが多く見られ、中央突破、王道路線を念頭に置いた作品名といえる。
            </Text>
          </CardBody>
        </Card>
      )}
    </For>
  </InfiniteScrollArea>
)
Copied!

ビューポートを指定する

ビューポートを指定する場合は、rootRefrefを設定します。

編集可能な例

const rootRef = useRef<HTMLDivElement>(null)
const [count, setCount] = useState<number>(50)
const resetRef = useRef<() => void>(() => {})

return (
  <VStack alignItems="flex-start" h="full">
    <Container
      ref={rootRef}
      flex="1"
      borderWidth="1px"
      rounded="md"
      p="md"
      overflowY="auto"
    >
      <InfiniteScrollArea
        rootRef={rootRef}
        resetRef={resetRef}
        onLoad={ ({ index, finish }) => {
          console.log("load", index)

          setCount((prev) => prev + 50)

          if (index >= 5) finish()
        }}
        loading={<Loading fontSize="2xl" />}
      >
        <For each={Array.from({ length: count })}>
          {(_, index)=>(
            <Card key={index}>
              <CardHeader>
                <Heading size="md">俺を誰だと思っていやがるッ!!</Heading>
              </CardHeader>

              <CardBody>
                <Text>
                  『天元突破グレンラガン』は、ガイナックス・アニプレックス・コナミデジタルエンタテインメント製作の日本のロボットアニメ作品。
                </Text>

                <Text>
                  作品名の「天元」とは、万物生育の根源という意味があり、また囲碁の用語では碁盤の中央(中心)を指す。劇中のキーワードにも螺旋、ドリル、回転など、中央・中心に関連するものが多く見られ、中央突破、王道路線を念頭に置いた作品名といえる。
                </Text>
              </CardBody>
            </Card>
          )}
        </For>
      </InfiniteScrollArea>
    </Container>

    <Button onClick={() => resetRef.current()}>Reset</Button>
  </>
)
Copied!

rootMarginを設定する

rootMarginを設定する場合は、rootMarginに文字列を設定します。

編集可能な例

const [count, setCount] = useState<number>(50)

return (
  <InfiniteScrollArea
    onLoad={({ index, finish }) => {
      console.log("load", index)

      setCount((prev) => prev + 50)

      if (index >= 5) finish()
    }}
    loading={<Loading fontSize="2xl" />}
    rootMargin="300px 0px 0px 0px"
  >
    <For each={Array.from({ length: count })}>
      {(_, index) => (
        <Card key={index}>
          <CardHeader>
            <Heading size="md">俺を誰だと思っていやがるッ!!</Heading>
          </CardHeader>

          <CardBody>
            <Text>
              『天元突破グレンラガン』は、ガイナックス・アニプレックス・コナミデジタルエンタテインメント製作の日本のロボットアニメ作品。
            </Text>

            <Text>
              作品名の「天元」とは、万物生育の根源という意味があり、また囲碁の用語では碁盤の中央(中心)を指す。劇中のキーワードにも螺旋、ドリル、回転など、中央・中心に関連するものが多く見られ、中央突破、王道路線を念頭に置いた作品名といえる。
            </Text>
          </CardBody>
        </Card>
      )}
    </For>
  </InfiniteScrollArea>
)
Copied!

thresholdを設定する

thresholdを設定する場合は、thresholdに数値を設定します。

編集可能な例

const [count, setCount] = useState<number>(50)

return (
  <InfiniteScrollArea
    onLoad={({ index, finish }) => {
      console.log("load", index)

      setCount((prev) => prev + 50)

      if (index >= 5) finish()
    }}
    loading={<Loading fontSize="2xl" />}
    threshold={1}
  >
    <For each={Array.from({ length: count })}>
      {(_, index) => (
        <Card key={index}>
          <CardHeader>
            <Heading size="md">俺を誰だと思っていやがるッ!!</Heading>
          </CardHeader>

          <CardBody>
            <Text>
              『天元突破グレンラガン』は、ガイナックス・アニプレックス・コナミデジタルエンタテインメント製作の日本のロボットアニメ作品。
            </Text>

            <Text>
              作品名の「天元」とは、万物生育の根源という意味があり、また囲碁の用語では碁盤の中央(中心)を指す。劇中のキーワードにも螺旋、ドリル、回転など、中央・中心に関連するものが多く見られ、中央突破、王道路線を念頭に置いた作品名といえる。
            </Text>
          </CardBody>
        </Card>
      )}
    </For>
  </InfiniteScrollArea>
)
Copied!

初回に読み込む

初回に読み込む場合は、initialLoadtrueに設定します。デフォルトでは、initialLoadfalseに設定されており、初回(index=0)のonLoadは実行されません。

true: スクロール量に関わらず、初回のonLoadは実行され、提供されるindex0から始まります。
false: スクロールが一定に達するとonLoadが実行され、提供されるindex1から始まります。

編集可能な例

const [count, setCount] = useState<number>(0)

return (
  <InfiniteScrollArea
    initialLoad
    onLoad={async ({ index, finish }) => {
      console.log("load", index)

      await wait(1000)

      setCount((prev) => prev + 50)

      if (index >= 5) finish()
    }}
    loading={<Loading fontSize="2xl" />}
  >
    <For each={Array.from({ length: count })}>
      {(_, index) => (
        <Card key={index}>
          <CardHeader>
            <Heading size="md">俺を誰だと思っていやがるッ!!</Heading>
          </CardHeader>

          <CardBody>
            <Text>
              『天元突破グレンラガン』は、ガイナックス・アニプレックス・コナミデジタルエンタテインメント製作の日本のロボットアニメ作品。
            </Text>

            <Text>
              作品名の「天元」とは、万物生育の根源という意味があり、また囲碁の用語では碁盤の中央(中心)を指す。劇中のキーワードにも螺旋、ドリル、回転など、中央・中心に関連するものが多く見られ、中央突破、王道路線を念頭に置いた作品名といえる。
            </Text>
          </CardBody>
        </Card>
      )}
    </For>
  </InfiniteScrollArea>
)
Copied!

開始するindexを変更する

開始するindexを変更する場合は、startIndexに数値を設定します。デフォルトは、1です。

編集可能な例

const [count, setCount] = useState<number>(50)

return (
  <InfiniteScrollArea
    onLoad={async ({ index, finish }) => {
      console.log("load", index)

      setCount((prev) => prev + 50)

      if (index >= 5) finish()
    }}
    loading={<Loading fontSize="2xl" />}
    startIndex={3}
  >
    <For each={Array.from({ length: count })}>
      {(_, index) => (
        <Card key={index}>
          <CardHeader>
            <Heading size="md">俺を誰だと思っていやがるッ!!</Heading>
          </CardHeader>

          <CardBody>
            <Text>
              『天元突破グレンラガン』は、ガイナックス・アニプレックス・コナミデジタルエンタテインメント製作の日本のロボットアニメ作品。
            </Text>

            <Text>
              作品名の「天元」とは、万物生育の根源という意味があり、また囲碁の用語では碁盤の中央(中心)を指す。劇中のキーワードにも螺旋、ドリル、回転など、中央・中心に関連するものが多く見られ、中央突破、王道路線を念頭に置いた作品名といえる。
            </Text>
          </CardBody>
        </Card>
      )}
    </For>
  </InfiniteScrollArea>
)
Copied!

方向を変更する

方向を変更する場合は、orientationverticalまたはhorizontalを設定します。デフォルトは、verticalです。

編集可能な例

const [count, setCount] = useState<number>(50)

return (
  <InfiniteScrollArea
    orientation="horizontal"
    h="full"
    onLoad={({ index, finish }) => {
      setCount((prev) => prev + 50)

      if (index >= 5) finish()
    }}
    loading={<Loading fontSize="2xl" />}
  >
    <For each={Array.from({ length: count })}>
      {(_, index) => (
        <Card key={index} minW="sm" h="full">
          <CardHeader>
            <Heading size="md">『天元突破グレンラガン』</Heading>
          </CardHeader>

          <CardBody>
            <Image
              src="https://www.gurren-lagann.net/tv/images/kv.jpg"
              w="full"
            />
          </CardBody>
        </Card>
      )}
    </For>
  </InfiniteScrollArea>
)
Copied!

反転させる

反転させる場合は、isReversetrueに設定します。デフォルトは、falseです。

編集可能な例

const rootRef = useRef<HTMLDivElement>(null)
const [count, setCount] = useState<number>(50)

return (
  <Box ref={rootRef} h="full" overflow="auto">
    <InfiniteScrollArea
      onLoad={({ index, finish }) => {
        console.log("load", index)

        setCount((prev) => prev + 50)

        if (index >= 5) finish()
      }}
      loading={<Loading fontSize="2xl" />}
      rootRef={rootRef}
      isReverse
    >
      <For each={Array.from({ length: count })}>
        {(_, index) => (
          <Card key={index}>
            <CardHeader>
              <Heading size="md">俺を誰だと思っていやがるッ!!</Heading>
            </CardHeader>

            <CardBody>
              <Text>
                『天元突破グレンラガン』は、ガイナックス・アニプレックス・コナミデジタルエンタテインメント製作の日本のロボットアニメ作品。
              </Text>

              <Text>
                作品名の「天元」とは、万物生育の根源という意味があり、また囲碁の用語では碁盤の中央(中心)を指す。劇中のキーワードにも螺旋、ドリル、回転など、中央・中心に関連するものが多く見られ、中央突破、王道路線を念頭に置いた作品名といえる。
              </Text>
            </CardBody>
          </Card>
        )}
      </For>
    </InfiniteScrollArea>
  </Box>
)
Copied!

無効にする

無効にする場合は、isDisabledtrueに設定します。これは、特定の条件下でスクロールに合わせてonLoadを実行したくない場合に有効です。

編集可能な例

const [isDisabled, setIsDisabled] = useState<boolean>(false)
const [count, setCount] = useState<number>(50)

return (
  <VStack alignItems="flex-start" h="full">
    <InfiniteScrollArea
      flex="1"
      borderWidth="1px"
      rounded="md"
      p="md"
      overflowY="auto"
      onLoad={async ({ index, finish }) => {
        console.log("load", index)

        setCount((prev) => prev + 50)

        if (index >= 5) finish()
      }}
      loading={<Loading fontSize="2xl" />}
      isDisabled={isDisabled}
    >
      <For each={Array.from({ length: count })}>
        {(_, index) => (
          <Card key={index}>
            <CardHeader>
              <Heading size="md">俺を誰だと思っていやがるッ!!</Heading>
            </CardHeader>

            <CardBody>
              <Text>
                『天元突破グレンラガン』は、ガイナックス・アニプレックス・コナミデジタルエンタテインメント製作の日本のロボットアニメ作品。
              </Text>

              <Text>
                作品名の「天元」とは、万物生育の根源という意味があり、また囲碁の用語では碁盤の中央(中心)を指す。劇中のキーワードにも螺旋、ドリル、回転など、中央・中心に関連するものが多く見られ、中央突破、王道路線を念頭に置いた作品名といえる。
              </Text>
            </CardBody>
          </Card>
        )}
      </For>
    </InfiniteScrollArea>

    <Button
      colorScheme={isDisabled ? "success" : "danger"}
      onClick={() => setIsDisabled((prev) => !prev)}
    >
      {isDisabled ? "Enable" : "Disabled"}
    </Button>
  </VStack>
)
Copied!

リセットする

indexをリセットする場合は、resetRefrefを設定します。設定されたrefにコールバック関数が付与されるので、それを実行します。

編集可能な例

const resetRef = useRef<() => void>(() => {})
const [count, setCount] = useState<number>(50)

return (
  <VStack alignItems="flex-start" h="full">
    <InfiniteScrollArea
      flex="1"
      borderWidth="1px"
      rounded="md"
      p="md"
      overflowY="auto"
      onLoad={async ({ index, finish }) => {
        console.log("load", index)

        setCount((prev) => prev + 50)

        if (index >= 5) finish()
      }}
      loading={<Loading fontSize="2xl" />}
      resetRef={resetRef}
    >
      <For each={Array.from({ length: count })}>
        {(_, index) => (
          <Card key={index}>
            <CardHeader>
              <Heading size="md">俺を誰だと思っていやがるッ!!</Heading>
            </CardHeader>

            <CardBody>
              <Text>
                『天元突破グレンラガン』は、ガイナックス・アニプレックス・コナミデジタルエンタテインメント製作の日本のロボットアニメ作品。
              </Text>

              <Text>
                作品名の「天元」とは、万物生育の根源という意味があり、また囲碁の用語では碁盤の中央(中心)を指す。劇中のキーワードにも螺旋、ドリル、回転など、中央・中心に関連するものが多く見られ、中央突破、王道路線を念頭に置いた作品名といえる。
              </Text>
            </CardBody>
          </Card>
        )}
      </For>
    </InfiniteScrollArea>

    <Button onClick={() => resetRef.current()}>Reset</Button>
  </VStack>
)
Copied!

スクロールの終わりに要素を表示する

スクロールの終わりに要素を表示する場合は、finishReactNodeを設定します。

編集可能な例

const [count, setCount] = useState<number>(50)

return (
  <InfiniteScrollArea
    onLoad={({ index, finish }) => {
      console.log("load", index)

      setCount((prev) => prev + 50)

      if (index >= 1) finish()
    }}
    loading={<Loading fontSize="2xl" />}
    finish={<>Finished</>}
  >
    <For each={Array.from({ length: count })}>
      {(_, index) => (
        <Card key={index}>
          <CardHeader>
            <Heading size="md">俺を誰だと思っていやがるッ!!</Heading>
          </CardHeader>

          <CardBody>
            <Text>
              『天元突破グレンラガン』は、ガイナックス・アニプレックス・コナミデジタルエンタテインメント製作の日本のロボットアニメ作品。
            </Text>

            <Text>
              作品名の「天元」とは、万物生育の根源という意味があり、また囲碁の用語では碁盤の中央(中心)を指す。劇中のキーワードにも螺旋、ドリル、回転など、中央・中心に関連するものが多く見られ、中央突破、王道路線を念頭に置いた作品名といえる。
            </Text>
          </CardBody>
        </Card>
      )}
    </For>
  </InfiniteScrollArea>
)
Copied!

トリガーをカスタマイズする

トリガーをカスタマイズする場合は、triggerPropspropsを設定します。

編集可能な例

const [count, setCount] = useState<number>(50)

return (
  <InfiniteScrollArea
    onLoad={async ({ index, finish }) => {
      console.log("load", index)

      await wait(5000)

      setCount((prev) => prev + 50)

      if (index >= 5) finish()
    }}
    loading={<Loading fontSize="2xl" />}
    triggerProps={{ bg: "primary.50", p: "md", rounded: "md" }}
  >
    <For each={Array.from({ length: count })}>
      {(_, index) => (
        <Card key={index}>
          <CardHeader>
            <Heading size="md">俺を誰だと思っていやがるッ!!</Heading>
          </CardHeader>

          <CardBody>
            <Text>
              『天元突破グレンラガン』は、ガイナックス・アニプレックス・コナミデジタルエンタテインメント製作の日本のロボットアニメ作品。
            </Text>

            <Text>
              作品名の「天元」とは、万物生育の根源という意味があり、また囲碁の用語では碁盤の中央(中心)を指す。劇中のキーワードにも螺旋、ドリル、回転など、中央・中心に関連するものが多く見られ、中央突破、王道路線を念頭に置いた作品名といえる。
            </Text>
          </CardBody>
        </Card>
      )}
    </For>
  </InfiniteScrollArea>
)
Copied!

ローディングをカスタマイズする

ローディングをカスタマイズする場合は、loadingReactNodeを設定します。

編集可能な例

const [count, setCount] = useState<number>(50)

return (
  <InfiniteScrollArea
    onLoad={async ({ index, finish }) => {
      console.log("load", index)

      await wait(5000)

      setCount((prev) => prev + 50)

      if (index >= 5) finish()
    }}
    loading={<>Loading…</>}
  >
    <For each={Array.from({ length: count })}>
      {(_, index) => (
        <Card key={index}>
          <CardHeader>
            <Heading size="md">俺を誰だと思っていやがるッ!!</Heading>
          </CardHeader>

          <CardBody>
            <Text>
              『天元突破グレンラガン』は、ガイナックス・アニプレックス・コナミデジタルエンタテインメント製作の日本のロボットアニメ作品。
            </Text>

            <Text>
              作品名の「天元」とは、万物生育の根源という意味があり、また囲碁の用語では碁盤の中央(中心)を指す。劇中のキーワードにも螺旋、ドリル、回転など、中央・中心に関連するものが多く見られ、中央突破、王道路線を念頭に置いた作品名といえる。
            </Text>
          </CardBody>
        </Card>
      )}
    </For>
  </InfiniteScrollArea>
)
Copied!

GitHubでこのページを編集する

ScrollAreaColorSwatch