admin管理员组

文章数量:1309955

I have a Next.js project, which is a Telegram Mini-App. It's a simple ecommerce template, and I use TypeScript and React. To have access to the current Telegram user or Mini-App methods globally I use the useContext() hook. I have ./lib/TelegramProvider.tsx file that handles that. It looks like this:

"use client";
import Script from "next/script";
import { createContext, useContext, useEffect, useMemo, useState } from "react";
import { postEvent } from "@telegram-apps/sdk";
import { on } from "@telegram-apps/bridge";
import { init } from "@telegram-apps/sdk";
import type { ITelegramUser, IWebApp } from "./types";

export interface ITelegramContext {
  webApp?: IWebApp;
  user?: ITelegramUser;
}

export const TelegramContext = createContext<ITelegramContext>({});

export const TelegramProvider = ({
  children,
}: {
  children: React.ReactNode;
}) => {
  const [webApp, setWebApp] = useState<any | null>(null);

  useEffect(() => {
    const app = (window as any)?.Telegram?.WebApp;
    if (app) {
      app.ready();
      setWebApp(app);

      // Global rules
      //   app.enableClosingConfirmation(); // Enable closing confirmation
      app.disableVerticalSwipes(); // Disable vertical swipes
      app.requestFullscreen();
    }
  }, []);

  const value = useMemo(() => {
    return webApp
      ? {
          webApp,
          unsafeData: webApp.initDataUnsafe,
          user: webApp.initDataUnsafe?.user,
        }
      : {};
  }, [webApp]);

  return (
    <TelegramContext.Provider value={value}>
      <Script
        src=".js"
        strategy="beforeInteractive"
      />
      {children}
    </TelegramContext.Provider>
  );
};

export const useTelegram = () => useContext(TelegramContext);

Then, I wrap all the content of the app in <TelegramProvider><TelegramProvider/> in ./src/app/layout.tsx

import type { Metadata } from "next";
import "./globals.css";
import HeaderWithRoundedCorners from "./components/HeaderWithRoundedCorners";
import { TelegramProvider } from "../../lib/TelegramProvider";


export const metadata: Metadata = {
  title: "My app",
  description: "My app description",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
   

  return (
    <html lang="en" suppressHydrationWarning>
      <head>
        <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, maximum-scale=1.0, user-scalable=0"/>

      </head>
      <body className={`antialiased`}>
        <div className="wrapper">
            <HeaderWithRoundedCorners><></></HeaderWithRoundedCorners>
            <TelegramProvider>{children}</TelegramProvider>
        </div>
      </body>
    </html>
  );
}

So that later, I can access it in ./src/app/product/[slug]/page.tsx like this:

"use client";
import { useTelegram } from "../../../../lib/TelegramProvider";
import React, { useEffect, useState } from "react";
import { useParams, notFound } from "next/navigation";

import ProductTabs from "../components/ProductTabs";
import Carousel from "../components/Carousel";
import PriceDisplay from "../components/PriceDisplay";
import DeliveryInfo from "../components/DeliveryInfo";

// export const products = [] dummy array

const ProductPage: React.FC = () => {
  const { slug } = useParams();
  const { webApp, user } = useTelegram(); // Access Telegram user and app data
  
  const product = products.find((p) => p.id === slug) || null;
  if (!product) return notFound();

  {/* return product component code, I can use user.username to display the username */}
  return (
    <div className="">
      {/* Display Telegram username for testing */}
      {user ? (
        <div className="mb-4 text-sm text-gray-500">
          Logged in as: <span className="font-bold">{user.username}</span>
        </div>
      ) : (
        <div className="mb-4 text-sm text-red-500">
          User data not available. Make sure to open this app in Telegram.
        </div>
      )}

      {/* Carousel Section */}
      <div className="mb-6">
        <Carousel images={product.images} peek="20" />
      </div>

      {/* Price Section */}
      <div className="mb-6">
        <PriceDisplay
          price={product.price}
          previousPrice={product.previousPrice}
        />
      </div>

      {/* Delivery Info Section */}
      <div className="mb-6">
        <DeliveryInfo {...deliveryData} />
      </div>

      {/* Page Header */}
      <h1 className="text-2xl font-bold mx-4">{product.name}</h1>

      {/* Product Tabs Section */}
      <ProductTabs
        description={product.description}
        properties={product.properties}
      />
    </div>
  );
};

export default ProductPage;

The problem is that, I currently rely on the <Script src=".js" strategy="beforeInteractive"/> line in my TelegramProvider for @telegram-apps/sdk to work. The SDK doesn't function without this line. I want to remove it and work only with the SDK, as it is recommended in their documentation. But whenever I remove it, the app breaks. I suspect it is because I can't properly initialize it. I've been trying to debug and make at least app.requestFullscreen(); work, but no luck. It is very confusing, the SDK appears to be dependant on telegram-web-app.js, although it is meant to be used standalone. Coming to StackOverflow is truly my last resort.

  1. I tried simply removing the <Script src=".js" strategy="beforeInteractive"/> line. I expected the app to break and it did.
  2. Then, I realized that I need to initialize it per the documentation. I import { init } from '@telegram-apps/sdk'; at the top of TelegramProvider and then tried calling init().
  3. I called init(); inside of the useEffect hook, right before declaring the app const. I expected it to work just like that. It didn't. I called init() after the app declaration, no luck. Then, I called it inside of the if statement. No luck. Then I called it right after declaring the ITelegramContext interface, and it didn't work still.
  4. I realized that I clearly had a gap of understanding of the SDK and I spent some time reading the documentation. I learned quite a lot, including the fact that I could've used more suitable @telegram-apps/sdk-react version, but it didn't get me anywhere near understanding how to initialize the library.
  5. I went on GitHub and started searching if I could find a code where people have already implemented this function, but no luck.
  6. I went looking inside the module itself, and only found the declaration of the function in @telegram-apps/sdk/dist/dts/init.d.ts, not the body. I was hoping to see what this function does to understand where exactly I should be putting it.

本文标签: reactjsHow can I make telegramappssdk work without telegramwebappjsStack Overflow