javascriptreactjsnext.jsgiphy

Unable to switch between giphy.trending and giphy.search


I have a chat application using NextJS and I'm trying to add a way to send GIPHY images.

I have things set up but I'm having trouble switching between the giphy.search() and giphy.trending() calls. Basically I have a component that displays the grid that contains the trending GIFs at that time. But above that grid, I have a text input where the user can search for specific GIFs. The value of this search input is stored in the parent component's state.

I initially tried having just one component for showing the grid (only trending):

<Grid
  fetchGifs={(offset: number) => giphy.trending({ offset: offset, limit: 10 })}
  width={width}
  columns={2}
  gutter={8}
  onGifClick={onClick}
/>

Since that worked, I tried to add the ability to search:

<Grid
  fetchGifs={
    (offset: number) => {
      if (searchTerm) {
        return giphy.search(searchTerm, { sort: 'relevant', lang: 'en', offset: offset, limit: 10 });
      } else {
        return giphy.trending({ offset: offset, limit: 10 });
      }
    }
  }
  width={width}
  columns={2}
  gutter={8}
  onGifClick={onClick}
/>

However, the SDK is erroring out. So I ended up making two separate components - one for the trending GIFs, and the other for a searchable GIFs:

import { Grid } from '@giphy/react-components';
import { GiphyFetch } from '@giphy/js-fetch-api';
import Constants from '@/utilities/constants';
import { GIFFetcherProps } from '@/types';

const TrendingGIPHY = ({ width, onClick }: GIFFetcherProps) => {
  const giphy = new GiphyFetch(Constants.GIPHY_API_KEY);

  return (
    <Grid
      fetchGifs={(offset: number) => giphy.trending({ offset: offset, limit: 10 })}
      width={width}
      columns={2}
      gutter={8}
      onGifClick={onClick}
    />
  );
};

export default TrendingGIPHY;
import { Grid } from '@giphy/react-components';
import { GiphyFetch } from '@giphy/js-fetch-api';
import Constants from '@/utilities/constants';
import { SearchGIFFetcherProps } from '@/types';

const SearchGIPHY = ({ searchTerm, width, onClick }: SearchGIFFetcherProps) => {
  const giphy = new GiphyFetch(Constants.GIPHY_API_KEY);

  return (
    <Grid
      fetchGifs={(offset: number) =>
        giphy.search(searchTerm, { sort: 'relevant', lang: 'en', offset: offset, limit: 10 })
      }
      width={width}
      columns={2}
      gutter={8}
      onGifClick={onClick}
    />
  );
};

export default SearchGIPHY;

And then on the parent component, I just determine which GIPHY component to render:

{searchTerm ? (
  <SearchGIPHY
    searchTerm={searchTerm}
    width={width}
    onClick={handleGIFClick}
  />
) : (
  <TrendingGIPHY width={width} onClick={handleGIFClick} />
)}

This is somewhat working but not really. It's able to switch back and forth between the correct components based on the searchTerm. However, the searchable component only searches for the first letter. I'm out of ideas on how to implement this.


Solution

  • I couldn't find anything related to this approach anywhere, however, it seems like it uses some kind of technique to memoize the fetch so no unnecessary re-render and fetch will be done.

    Fortunately, after digging more doc which led me to their Github pate, it has a runnable demo and it has the working example! https://github.com/Giphy/giphy-js/blob/master/packages/react-components/README.md#bare-bones-example

    After reviewing their code, here's some thoughts

    1. Your implementation is fundamentally done correctly
    2. Turns out, Giphy really is doing some kind of memoization to their Grid component -- Their demo has a property for Grid component the your code doesn't have... which is key

    In other words, you can solve the problem where only first letter is being parsed by adding it, like this --

    <Grid
      key={searchTerm} // <-- HERE
      fetchGifs={(offset: number) =>
        giphy.search(searchTerm, { sort: 'relevant', lang: 'en', offset: offset, limit: 10 })
      }
      width={width}
      columns={2}
      gutter={8}
      onGifClick={onClick}
    />
    

    (the demo has the prop key to be more complex, but you can make your own judgement)

    key={`${channelSearch} ${term} ${activeChannel?.user.username}`}
    

    Reference