सर्वर साइड रेंडरिंग

reelkit के सभी पैकेज सर्वर पर चलते हैं। इन्हें Next.js, Remix, Angular SSR, Nuxt 3 या किसी भी SSR सेटअप में import और रेंडर करें।

यह कैसे काम करता है

core स्लाइडर कंट्रोलर शुद्ध logic है और बनाते समय DOM को नहीं छूता। जेस्चर listeners, कीबोर्ड इवेंट और एनिमेशन सिर्फ़ क्लाइंट साइड के lifecycle hooks में जुड़ते हैं।

SSR के दौरान React का Reel, size मिलने पर शुरू में दिखने वाली स्लाइड (आम तौर पर 3: पिछली, मौजूदा, अगली) के साथ एक स्टैटिक कंटेनर रेंडर करता है, और खुद नापने पर एक खाली कंटेनर। Hydration पर यह जेस्चर, कीबोर्ड और व्हील कंट्रोलर जोड़ता है, जिससे सब कुछ इंटरैक्टिव हो जाता है।

Vue का Reel सर्वर पर एक खाली कंटेनर रेंडर करता है और hydration के बाद स्लाइड बनाता है। size देने पर यह कंटेनर क्लाइंट के पहले रेंडर से मेल नहीं खाता, इसलिए Nuxt में इसे <ClientOnly> के अंदर रखा जाता है (देखें Nuxt 3)।

पैकेजSSR के लिए सुरक्षितटिप्पणी
@reelkit/coreहाँशुद्ध logic, import या निर्माण के समय कोई ब्राउज़र API नहीं
@reelkit/reactहाँReel और ReelIndicator सर्वर पर मान्य HTML रेंडर करते हैं
@reelkit/angularहाँStandalone कंपोनेंट, Angular SSR (@angular/ssr) के साथ SSR में काम करते हैं
@reelkit/vueहाँसर्वर पर import और रेंडर करना सुरक्षित है; size देने पर Nuxt 3 में Reel को <ClientOnly> के अंदर रखें
@reelkit/react-reel-playerहाँबंद होने पर (isOpen=false) कुछ भी रेंडर नहीं करता
@reelkit/react-lightboxहाँबंद होने पर (isOpen=false) कुछ भी रेंडर नहीं करता
@reelkit/angular-reel-playerहाँबंद होने पर (isOpen=false) कुछ भी रेंडर नहीं करता
@reelkit/angular-lightboxहाँबंद होने पर (isOpen=false) कुछ भी रेंडर नहीं करता
@reelkit/vue-reel-playerहाँबंद होने पर (isOpen=false) कुछ भी रेंडर नहीं करता
@reelkit/vue-lightboxहाँबंद होने पर (isOpen=false) कुछ भी रेंडर नहीं करता
@reelkit/stories-coreहाँफ़्रेमवर्क से स्वतंत्र, DOM तक कोई पहुँच नहीं
@reelkit/react-stories-playerहाँबंद होने पर (isOpen=false) कुछ भी रेंडर नहीं करता
@reelkit/angular-stories-playerहाँबंद होने पर (isOpen=false) कुछ भी रेंडर नहीं करता
@reelkit/vue-stories-playerहाँबंद होने पर (isOpen=false) कुछ भी रेंडर नहीं करता

Next.js App Router

Reel ब्राउज़र इवेंट और refs का इस्तेमाल करता है, इसलिए यह Client Component के रूप में चलता है। जिस फ़ाइल में Reel इस्तेमाल हो, उसके सबसे ऊपर "use client" directive जोड़ें:

tsx
'use client';

import { Reel, ReelIndicator } from '@reelkit/react';

export function Feed({ items }: { items: FeedItem[] }) {
  return (
    <Reel
      count={items.length}
      size={[400, 700]}
      direction="vertical"
      enableWheel
      itemBuilder={(index) => (
        <div className="w-full h-full flex items-center justify-center">
          {items[index].title}
        </div>
      )}
    >
      <ReelIndicator />
    </Reel>
  );
}

आप Server Component में डेटा fetch करके उसे नीचे पास कर सकते हैं:

tsx
// app/feed/page.tsx (Server Component)
import { Feed } from './Feed';

export default async function FeedPage() {
  const items = await fetchFeedItems();

  return <Feed items={items} />;
}

Next.js Pages Router

Pages Router बिना किसी अतिरिक्त कॉन्फ़िगरेशन के काम करता है। कंपोनेंट SSR के दौरान रेंडर होता है और क्लाइंट पर hydrate होता है:

tsx
// pages/feed.tsx
import { Reel } from '@reelkit/react';
import type { GetServerSideProps } from 'next';

interface Props {
  items: FeedItem[];
}

export const getServerSideProps: GetServerSideProps<Props> = async () => {
  const items = await fetchFeedItems();
  return { props: { items } };
};

export default function FeedPage({ items }: Props) {
  return (
    <Reel
      count={items.length}
      size={[400, 700]}
      itemBuilder={(index) => <Slide data={items[index]} />}
    />
  );
}

SSR के साथ रिस्पॉन्सिव साइज़

size prop को पूरी तरह छोड़ दें। size न देने पर Reel क्लाइंट पर ResizeObserver के ज़रिए अपना कंटेनर खुद नापता है। SSR के दौरान स्लाइडर एक खाली कंटेनर रेंडर करता है; hydration पर वह नापकर तुरंत स्लाइड रेंडर कर देता है:

tsx
'use client';

import { Reel } from '@reelkit/react';

export function FullScreenFeed({ items }: { items: FeedItem[] }) {
  return (
    <Reel
      count={items.length}
      style={{ width: '100%', height: '100dvh' }}
      itemBuilder={(index) => <Slide data={items[index]} />}
    />
  );
}
अपने-आप साइज़ कैसे काम करता है

size छोड़ने पर कंटेनर का साइज़ CSS से तय होना चाहिए (parent flex/grid, तय width/height या प्रतिशत)। पहला माप पूरा होने तक स्लाइडर कुछ भी रेंडर नहीं करता, फिर नापे गए आकार को भरता है और आगे के resize पर अपने-आप प्रतिक्रिया देता है।

तय साइज़ (मैन्युअल तरीका)

पिक्सेल-स्तर के नियंत्रण के लिए तय size prop पास करें। SSR के दौरान window.innerWidth उपलब्ध नहीं होता, इसलिए एक डिफ़ॉल्ट दें और mount पर उसे अपडेट करें:

tsx
'use client';

import { useState, useEffect } from 'react';
import { Reel } from '@reelkit/react';

// Default size for SSR — matches common mobile viewport
const DEFAULT_SIZE: [number, number] = [390, 844];

export function FullScreenFeed({ items }: { items: FeedItem[] }) {
  const [size, setSize] = useState<[number, number]>(DEFAULT_SIZE);

  useEffect(() => {
    const update = () =>
      setSize([window.innerWidth, window.innerHeight]);

    update();
    window.addEventListener('resize', update);
    return () => window.removeEventListener('resize', update);
  }, []);

  return (
    <Reel
      count={items.length}
      size={size}
      itemBuilder={(index) => <Slide data={items[index]} />}
    />
  );
}
सुझाव

ऐसा डिफ़ॉल्ट साइज़ चुनें जो आपके सबसे आम viewport से मेल खाए (जैसे mobile-first)। अगर असली viewport अलग है, तो hydration पर स्लाइडर तुरंत खुद को ठीक कर लेगा।

Overlay कंपोनेंट

ReelPlayerOverlay, LightboxOverlay और StoriesOverlay isOpen={false} होने पर कुछ भी रेंडर नहीं करते, इसलिए ये डिफ़ॉल्ट रूप से SSR के लिए सुरक्षित हैं। ये अपना portal सिर्फ़ खुलने पर mount करते हैं (आम तौर पर क्लाइंट पर यूज़र की किसी क्रिया से):

tsx
'use client';

import { useState } from 'react';
import { ReelPlayerOverlay } from '@reelkit/react-reel-player';

export function VideoFeed({ content }: { content: ContentItem[] }) {
  const [isOpen, setIsOpen] = useState(false);
  const [startIndex, setStartIndex] = useState(0);

  return (
    <>
      <div className="grid grid-cols-3 gap-1">
        {content.map((item, i) => (
          <button
            key={i}
            onClick={() => { setStartIndex(i); setIsOpen(true); }}
          >
            <img src={item.thumbnail} alt="" />
          </button>
        ))}
      </div>

      <ReelPlayerOverlay
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        content={content}
        initialIndex={startIndex}
      />
    </>
  );
}

Angular SSR

@angular/ssr के साथ सभी Angular कंपोनेंट SSR के लिए सुरक्षित हैं। स्लाइडर कंट्रोलर ngOnInit में बनता है, और जिस काम के लिए ब्राउज़र चाहिए, जैसे कंटेनर नापना, वह सर्वर पर isPlatformBrowser के ज़रिए छोड़ दिया जाता है। Overlay कंपोनेंट isOpen=false होने पर कुछ भी रेंडर नहीं करते, इसलिए सर्वर रेंडरिंग के दौरान कोई markup नहीं बनाते।

typescript
import { Component, signal } from '@angular/core';
import {
  RkReelPlayerOverlayComponent,
} from '@reelkit/angular-reel-player';

@Component({
  selector: 'app-feed',
  standalone: true,
  imports: [RkReelPlayerOverlayComponent],
  template: `
    <rk-reel-player-overlay
      [isOpen]="isOpen()"
      [content]="content"
      (closed)="isOpen.set(false)"
    />
  `,
})
export class FeedComponent {
  isOpen = signal(false);
  content = [/* ... */];
}

Nuxt 3

ReelKit के Vue कंपोनेंट सर्वर पर बिना किसी error के import और रेंडर होते हैं। Reel सर्वर से एक खाली कंटेनर भेजता है और hydration के बाद स्लाइड बनाता है। जब Reel अपना साइज़ खुद तय करता है, तो @reelkit/vue 0.9.1 से यह कंटेनर बिना mismatch के hydrate होता है; पुराने वर्ज़न में इसकी ऊँचाई नहीं बचती थी, इसलिए कोई स्लाइड नहीं दिखती थी। साफ़ size देने पर क्लाइंट के पहले रेंडर में ही स्लाइड होती हैं, जिससे hydration में mismatch होता है। ऐसे में, या पुराने वर्ज़न पर, Reel को <ClientOnly> कंपोनेंट में लपेटें या .client.vue suffix इस्तेमाल करें:

vue
<!-- pages/feed.vue -->
<script setup lang="ts">
const items = await useFetch('/api/feed');
</script>

<template>
  <ClientOnly>
    <Feed :items="items.data.value" />
  </ClientOnly>
</template>

Feed कंपोनेंट Reel को सामान्य तरीके से इस्तेमाल करता है:

vue
<!-- components/Feed.vue -->
<script setup lang="ts">
import { Reel, ReelIndicator } from '@reelkit/vue';

defineProps<{ items: FeedItem[] }>();
</script>

<template>
  <Reel :count="items.length" direction="vertical" enable-wheel>
    <template #item="{ index, size }">
      <div :style="{ width: size[0] + 'px', height: size[1] + 'px' }">
        {{ items[index].title }}
      </div>
    </template>
    <ReelIndicator />
  </Reel>
</template>

SSR के साथ रिस्पॉन्सिव साइज़

अपने-आप माप के लिए size prop छोड़ दें। Reel अपने parent के 100% आकार में फ़िट हो जाता है, और @reelkit/vue 0.9.1 से इसे <ClientOnly> की ज़रूरत नहीं: सर्वर पूरे आकार का एक खाली कंटेनर भेजता है, और क्लाइंट उसे नापकर स्लाइड रेंडर करता है। उदाहरण में wrapper रखा गया है, क्योंकि वह पुराने वर्ज़न पर भी काम करता है:

vue
<template>
  <ClientOnly>
    <div style="width: 100%; height: 100dvh">
      <Reel :count="items.length">
        <template #item="{ index, size }">
          <Slide :data="items[index]" :size="size" />
        </template>
      </Reel>
    </div>
  </ClientOnly>
</template>

Overlay कंपोनेंट

ReelPlayerOverlay, LightboxOverlay और StoriesOverlay isOpen false होने पर कुछ भी रेंडर नहीं करते, इसलिए इन्हें <ClientOnly> की ज़रूरत नहीं होती और सर्वर रेंडरिंग के दौरान ये कोई markup नहीं बनाते। ये अपनी सामग्री को body में तभी teleport करते हैं जब क्लाइंट पर खोले जाते हैं।

Core को सीधे इस्तेमाल करना

किसी कस्टम फ़्रेमवर्क इंटीग्रेशन के लिए @reelkit/core सीधे इस्तेमाल करते समय आप कंट्रोलर सर्वर पर बना सकते हैं। attach() और observe() क्लाइंट पर कॉल करें:

typescript
import { createSliderController } from '@reelkit/core';

// Safe to call on the server — no DOM access
const controller = createSliderController({
  count: 10,
  direction: 'vertical',
});

// Only call on the client — attaches DOM event listeners
if (typeof window !== 'undefined') {
  controller.attach(element);
  controller.observe();
}

सारांश

क्या सीधे काम करता है
  • सर्वर पर reelkit का कोई भी पैकेज import करना
  • SSR के दौरान स्लाइडर कंपोनेंट रेंडर करना (मान्य स्टैटिक HTML बनता है)
  • सर्वर पर कंट्रोलर बनाना
  • isOpen=false होने पर overlay कंपोनेंट
किन बातों का ध्यान रखें
  • अपने-आप माप के लिए size छोड़ दें, या viewport पर आधारित आकार इस्तेमाल करते समय एक डिफ़ॉल्ट दें
  • Nuxt में size देने पर, या 0.9.1 से पहले के @reelkit/vue पर, Vue का Reel <ClientOnly> के अंदर रेंडर करें
  • core को सीधे इस्तेमाल करते समय सर्वर पर attach()/observe() कॉल न करें