react-lazyload-list
v1.0.1
Published
A React component for lazy‑loading long lists using IntersectionObserver and MutationObserver, supporting automatic bottom scrolling and optional wrapper preservation.
Maintainers
Readme
react-lazyload-list
react-lazyload-list は、スクロール位置に応じて子要素を遅延ロード(レイジーロード)する汎用的なリストコンポーネントです。Wrapper と ExposeComponent が低レベルの可視性検知ロジックを提供し、useLazyLoad フックと LazyList がそれらを組み合わせて「一定数ずつ増やす」/「下からスクロールする」リストを実装します。
目次
インストール
# npm / yarn / pnpm いずれか
npm i react-lazyload-list # ※パッケージ名は例です。実際はローカルで src をコピーしてください。備考
このコンポーネントはreactとreact-domがインストールされている環境を前提にしています。IntersectionObserverとMutationObserverが利用できるブラウザで動作します(IE 11 以前はポリフィルが必要)。
主要エクスポートと API
Wrapper
export function Wrapper({
children,
rootMargin = '500px',
}: {
children: React.ReactNode;
rootMargin?: string;
}): JSX.Element役割
- 子要素 (
children) を 可視領域 になるまで 非描画 にし、IntersectionObserver がトリガーされた時点で実際にマウントします。 - 非表示時は高さを保持(
heightスタイル)することでレイアウト崩れを防止します。
パラメータ
| パラメータ | 型 | デフォルト | 説明 |
|-----------|----|------------|------|
| children | ReactNode | - | ラップしたいコンテンツ。可視になるまで実際には DOM に挿入されません。 |
| rootMargin | string | '500px' | IntersectionObserver の rootMargin。遠くの要素でも先取りしてロードしたい場合に調整します。 |
使用例
<Wrapper rootMargin="300px">
<MyHeavyComponent />
</Wrapper>ExposeComponent
export function ExposeComponent({
onVisibleChange,
onContentChange,
bindElementRef,
style,
rootMargin = '1500px',
children,
}: {
onVisibleChange: (isVisible: boolean) => void;
onContentChange?: () => void;
bindElementRef?: (el: HTMLDivElement | null) => void;
style?: React.CSSProperties;
rootMargin?: string;
children?: React.ReactNode;
}): JSX.Element役割
IntersectionObserver と MutationObserver を内部でセットアップし、下記 2 つのイベントを外部に通知します。
onVisibleChange(isVisible)– 要素がビューポートに入った/出たとき。onContentChange()– 子要素が増減したとき(childrenが動的に変化した場合)。
bindElementRefで外部から DOM 要素への参照を取得でき、ラッパーコンポーネントから高さ取得等に利用できます。
パラメータ
| パラメータ | 型 | デフォルト | 説明 |
|-----------|----|------------|------|
| onVisibleChange | (isVisible: boolean) => void | - | 可視状態が変化したら呼び出されるコールバック。 |
| onContentChange | () => void | undefined | 子要素が増減したときに呼び出されるコールバック。 |
| bindElementRef | (el: HTMLDivElement \| null) => void | undefined | ref を外部に渡すための関数。 |
| style | React.CSSProperties | null | 表示・非表示時の代替スタイル(幅 1px・高さ 1px 等)。 |
| rootMargin | string | '1500px' | IntersectionObserver のマージン。大きくすると早めにロードされます。 |
| children | ReactNode | null | 実際に表示したいコンテンツ。null のときは placeholder が描画されます。 |
使用例
<ExposeComponent
rootMargin="1000px"
onVisibleChange={v => console.log('visible:', v)}
onContentChange={() => console.log('content changed')}
bindElementRef={el => console.log('DOM element:', el)}
>
<div>遅延ロード対象</div>
</ExposeComponent>useLazyLoad
export function useLazyLoad({
initCount = 8,
stepCount = 3,
initDataLength,
rootMargin = '1500px',
}: {
initCount?: number;
stepCount?: number;
initDataLength: number;
rootMargin?: string;
}): [
showCount: number,
lazyLoadTrigger: JSX.Element | null
]役割
遅延ロードの状態管理 をフックとして提供します。
showCount: 現在画面に表示すべきアイテム数。lazyLoadTrigger:IntersectionObserverが付与された透明なExposeComponent(リスト末端に配置)。この要素が可視になるとshowCountがstepCount分増加します。
initCount(初期表示数) とstepCount(スクロールごとに追加表示数) を自由に設定可能です。
パラメータ
| パラメータ | 型 | デフォルト | 必須 | 説明 |
|-----------|----|------------|------|------|
| initCount | number | 8 | 任意 | 最初に描画する要素数。 |
| stepCount | number | 3 | 任意 | 交差時に追加で描画する要素数。 |
| initDataLength | number | - | 必須 | データ全体の長さ(items.length)。全件表示したら lazyLoadTrigger は null になります。 |
| rootMargin | string | '1500px' | 任意 | ExposeComponent の IntersectionObserver のマージン。 |
戻り値
showCount: 現在表示中のアイテム数(LazyListが内部で参照)。lazyLoadTrigger: リストの下端(または上端)に配置すべきコンポーネント。nullの場合は全件表示済みです。
使用例
const [showCount, LazyTrigger] = useLazyLoad({
initCount: 10,
stepCount: 5,
initDataLength: items.length,
});LazyList
export function LazyList(props: {
className?: string;
items: React.ReactNode[];
beginFromBottom?: boolean;
}): JSX.Element役割
useLazyLoadのロジックとWrapperコンポーネントを組み合わせ、遅延ロード付きスクロールリスト を生成します。beginFromBottomがtrueのときは「下から」スクロール(チャットUI など)に最適化し、マウント後に自動で下端へスクロールします。
パラメータ
| パラメータ | 型 | デフォルト | 説明 |
|-----------|----|------------|------|
| className | string | undefined | コンテナ <div> に付与する CSS クラス名。 |
| items | ReactNode[] | - | 表示したい要素の配列。(例:heights.map(h => <div style={{height:h}} />)) |
| beginFromBottom | boolean | true | true → リストを下部から描画し、マウント時に自動スクロール。false → 上部から描画。 |
使用例
<LazyList
className="chat-list"
items={messages.map(m => <MessageBubble data={m} />)}
beginFromBottom={true}
/>