react-tweet icon indicating copy to clipboard operation
react-tweet copied to clipboard

TypeError: Cannot read properties of undefined (reading 'screen_name')

Open AndonMitev opened this issue 2 years ago • 8 comments

Hello I'm getting this error:

- error node_modules\react-tweet\dist\utils.js (1:63) @ screen_name
- error TypeError: Cannot read properties of undefined (reading 'screen_name')
    at stringify (<anonymous>)

and use it like this:

import { Tweet } from 'react-tweet';

const MOCKED_TWEETS = ['mock_tweet#1', 'mock_tweet#2', 'mock_tweet#3'];

export default function TwitterFeed() {
  return (
    <div className="flex flex-col w-1/5">
      {MOCKED_TWEETS.map((tweetId) => (
        <Tweet key={tweetId} id={tweetId} />
      ))}
    </div>
  );
}

any ideas?

AndonMitev avatar Aug 28 '23 07:08 AndonMitev

Update to the latest version of react-tweet and try again 🙏

lfades avatar Sep 01 '23 14:09 lfades

I just came across this issue myself as well

This was the tweet id - 1658970955203641344

dillionverma avatar Sep 01 '23 17:09 dillionverma

It looks like fetching the tweet from X's syndication API doesn't return a valid JSON but a text/html content type. The weird part is that it works well locally but doesn't work when building in CI for prod.

fayez-nazzal avatar Sep 02 '23 10:09 fayez-nazzal

@fayez-nazzal could you isolate that issue in a reproduction and share it with me? This error can happen if the twitter API does change something in their API response unexpectedly but it shouldn't be the case that it works locally and fails in CI.

lfades avatar Sep 04 '23 17:09 lfades

I just came across this issue myself as well

This was the tweet id - 1658970955203641344

Looking at this tweet id, the api response is:

{"data":{"__typename":"TweetTombstone","tombstone":{"text":{"text":"You’re unable to view this Post because this account owner limits who can view their Posts. Learn more","entities":[{"from_index":92,"to_index":102,"ref":{"__typename":"TimelineUrl","url":"https://help.twitter.com/rules-and-policies/notices-on-twitter","url_type":"ExternalUrl"}}],"rtl":false}}}}

I haven't looked too closely at the code, but does the component validate the api response?

sarimabbas avatar Sep 13 '23 07:09 sarimabbas

I came across the same issue. It's happening for me on local dev environment as well

5yearsKim avatar Sep 24 '23 03:09 5yearsKim

+1

it crashes locally for me, haven't tried in prod

EDIT: One thing i've implemented is that i'm extending Tweet type with optional tombstone property and that fixed issue at least for me!

import type { VercelRequest, VercelResponse } from "@vercel/node";
import { getTweet, Tweet } from "react-tweet/api";

type ExtendedTweet =
  | (Tweet & {
      tombstone?: any;
    })
  | undefined;

const handler = async (req: VercelRequest, res: VercelResponse) => {
  const tweetId = req.query.tweet;

  if (req.method !== "GET" || typeof tweetId !== "string") {
    res.status(400).json({ error: "Bad Request." });
    return;
  }

  try {
    const tweet: ExtendedTweet = await getTweet(tweetId);
    if (tweet?.tombstone) {
      res.status(404).json({ error: "Tweet deleted", data: tweet });
      return;
    }
    res.status(tweet ? 200 : 404).json({ data: tweet ?? null });
  } catch (error: any) {
    console.error(error);
    res.status(400).json({ error: error.message ?? "Bad request." });
  }
};

export default handler;

I'm sharing piece of code that i've added in case it helps someone!

nakedfool avatar Oct 08 '23 09:10 nakedfool

Sharing my solve for this using nextjs 14 app router:

  • Have to use getTweet on serverside so wrapping it in a server api api/tweet/[id]/route.ts:
import { NextRequest, NextResponse } from "next/server";
import { getTweet } from "react-tweet/api";

const handler = async ( request: NextRequest, { params }: { params: { id: string } } ) => {
  try {
    const id = params?.id || (await (request.json() as any)?.id);
    if (!id) {
      return NextResponse.json({ error: 'id is required' }, { status: 400 });
    }

    const tweet = await getTweet(id);
    // useTweet requires this be inside of `data` property
    return NextResponse.json({ data: tweet ?? null }, { status: tweet ? 200 : 404});
  } catch (error: any) {
    console.log(error);
    return NextResponse.json(error.message, { status: error.statusCode || 500, statusText: error.message });
  }
}

export { handler as POST, handler as GET };
  • Client side can use EmbeddedTweet, TweetNotFound, TweetSkeleton:
'use client'

import { EmbeddedTweet, TweetNotFound, TweetSkeleton, useTweet, type TweetProps } from 'react-tweet';

export const Tweet = (props: TweetProps) => {
  const { id, components, ...rest } = props;
  const { data, error, isLoading } = useTweet(id, `/api/tweet/${id}`);

  if (error) {
    const NotFound = components?.TweetNotFound || TweetNotFound;
    return <NotFound error={error} />;
  }
  if (isLoading || !data) {
    return <TweetSkeleton />;
  }
  return (
    <div className="my-6">
      <div className={`flex justify-center`}>
        <EmbeddedTweet tweet={data} components={components} {...rest} />
      </div>
    </div>
  );
};

bebeal avatar Apr 04 '24 23:04 bebeal