reactjs - როგორ გადავამუღოთ სერვერზე დაყვანილი Apollo ქეში სწორად, როდესაც იყენებთ `renderToPipeableStream`?


მე ვაკეთებ SSR-ის React-ის renderToPipeableStream-ის გამოყენებით და ვხმარობ ApolloClient-ს კომპონენტებში მონაცემების მისაღებად. იმისათვის, რომ კეში აღდგეს სერვერიდან კლიენტზე, აუცილებელია კეშის გამოტანა და მისი დამატება გლობალურ window ობიექტზე HTML-ში ჩაშენებული inline სკრიპტის საშუალებით, რომელიც გამოგზავნილია სერვერის მიერ.

მადლობა ღმერთს, React 18 აკონტროლებს Suspense-ს SSR-ის დროს და შემიძლია უბრალოდ შევაჩერო სკრიპტის ტეგის გამოჩენა, რომელიც შეიცავს კეშს, სანამ ყველა მოთხოვნა არ იქნება დასრულებული.

export const ApolloSSRCache = () => {
  Object.values(renderCache).forEach((wrapped) => wrapped());
  return (
    <script
      dangerouslySetInnerHTML={{
        __html: `window.__APOLLO_STATE__=${JSON.stringify(
          client.extract()
        ).replace(/</g, '\<')};`,
      }}
    />
  );
};

განცხადებები გარშემორტყმულია ორფერიებით, რომლებიც გპირდებიან შეცდომას თუ არ იქნება განსაზღვრული.

export function wrapPromise<T>(promise: Promise<T>): () => T {
  let status = 'pending';
  let response: T;
  const suspender = promise.then(
    (res) => {
      status = 'success';
      response = res;
    },
    (err) => {
      status = 'error';
      response = err;
    }
  );
  return () => {
    switch (status) {
      case 'pending':
        throw suspender;
      case 'error':
        throw response;
      default:
        return response;
    }
  };
}

ეს მუშაობს და ყველა მოთხოვნა, რომელიც გაკეთებულია ნებისმიერ კომპონენტში სერვერის მხრიდან რენდერირების დროს, ახდენს აღდგენას კლიენტის მხარის ქეშში, რაც ნიშნავს, რომ კლიენტზე useQuery ჰუკი შეუძლია გამოიყენოს ქეში, რათა დაუყოვნებლივ მოემსახუროს პასუხი. ეს აუცილებელია, წინააღმდეგ შემთხვევაში თქვენ განახორციელებთ მოთხოვნების რაოდენობას ორჯერ, და შესაძლოა გამოიწვიოს ფლიკერინგი, თუ გამოჩნდება ლოდინის მდგომარეობა მონაცემების მიღების დროს კლიენტზე.

ამ მომენტში მე უნდა ვაკონტროლო მოთხოვნები/დაპირებები ხელით და დაველოდო, სანამ ყველა იქნება დასრულებული. ცოტა ტექნიკური მოგეჩვენება ყველა მოთხოვნის კონტროლი, რომელიც შექმნილია Apollo-ს მიერ, თუ Apollo-მ უკვე აქვს ქეში, რომელიც იცის ყველა მოთხოვნის მდგომარეობის შესახებ.

ვინმეს ხომ არ უნახავს, არსებობს თუ არა სწორი გზა კეშის გამოტანისა და აღდგენისთვის სტრიმზე რენდერის დროს?

ამისთვის საჭიროა მუშაობა Suspense-თან, რადგან მე ვიყენებ კოდი განაწილებას დინამიური იმპორტებით.

განახლება: თუ სერვერზე იყენებთ useSuspenseQuery და განათავსებთ სკრიპტის ტეგს, რომელიც გამოტანას უწევს თქვენს ქეშს, Render-ებული შვილების ქვემოთ, ქეში კარგად დაიფარება, რადგან შეკითხვის შესრულების კომპონენტები შეჩერდებიან.

ამიტომ საჭიროება არ არის ტეგის ხელით დაყოვნებისა, რადგან client.extract() გამოიძახება ყველა მოთხოვნის გადაწყვეტის შემდეგ.

განახლება 2: useSuspenseQuery იგნორირებს {fetchPolicy: 'network-only'} და სერვერზე წერის დროს მოიხმარს ქეშირებულ მონაცემებს ვიდრე სერვერი არ გადაიტვირთება.

პასუხი #1

ამ მომენტისთვის React-ში ამას ოფიციალური გზით შესრულება შეუძლებელია.

თუ გსურთ მეტი გაიგოთ React-ის „დაკარგული ფუნქციების“ შესახებ და მის ფონზე, მაქვს კონფერენციის პრეზენტაცია ამ თემაზე: https://portal.gitnation.org/contents/the-rocky-journey-of-data-fetching-libraries-in-reacts-new-streaming-ssr

ამის აღნიშვნით, ეს საკმაოდ კარგად მუშაობს (რამდენიმე ხაკის გამოყენებით) Next.js-ში @apollo/experimental-nextjs-app-support პაკეტის გამოყენებით, და ამჟამად ჩვენ ვქმნით ახალ @apollo/client-react-streaming პაკეტს, რომელიც ასევე საშუალებას მისცემს ამის გამოყენებას სხვა გარემოებებში.

ჩვენ ალბათ გამოვაქვეყნებთ ამას მომავალი რამდენიმე კვირის განმავლობაში.

მე გირჩევთ გაგრძელოთ ამ PR-ის მონიტორინგი, რომელიც შეიცავს ინტეგრაციის ტესტს Vite + renderToReadableStream-ისთვის (და სხვა 0.9.0 PR-ებისთვის) - renderToPipeableStream გამოყენება ცოტა განსხვავებულად მოხდება, ამას შეგიძლიათ შეხედოთ React-ის იმ ვერსიით, რომელიც გაფართოვებულია გარკვეული "ჰაკერული hooks"-ებით ამ ინტეგრაციის ტესტ PR-ში.

ამის თქმის შემდეგ: ჩვენ არ მივცეთ მხარდაჭერა useQuery სტრიმინგ SSR-ში. Apollo Client ახლა უკვე გადის სუსპენსზე მომზადებულ ჰუქებთან, როგორიცაა useSuspenseQuery, ამიტომ ჩვენ ვფოკუსობთ მათზე. useQuery აისახება მხოლოდ ერთხელ, და შედეგად ყოველთვის აჩვენებს დატვირთვის მდგომარეობას სერვერზე - და თქვენ შეიქმნებოდათ რეჰაიდრაციის არასაკმარისი შესაბამისობა ბრაუზერში, თუ სცდილობთ მონაცემების გადასატანად.