Let's build a Meme app with react in 1 hour
Published: 2022-06-22 08:21:45

Hello, today we are gonna build a Meme app with react.js. Here is the link to the github [repo](https://github.com/Sadeedpv/Memegenerator) and here is the [link](https://sadeedpv.github.io/Memegenerator/) to the website. This app is build with the [Meme Api](https://github.com/D3vd/Meme_Api).

This is a pretty simple app and this tutorial is for absolute beginners. Okay let's start by creating the react app with the command

```
npx create-react-app <Appname>
```
And let's clean up the folders and start fresh. Run the command to start the app

```
npm start
```

If there are no errors, you should see a blank screen. In the 'src' folder, let's create a new folder called 'components' and modify your app.js file like this.

```
import Header from "./components/Header";
import Post from "./components/Post";

function App() {
  return (
    <>
    <Header />
    <Post />
    </>
  );
}
```

Okay, here we declare two components called Header and Post(which we haven't made yet). Now come to the components folder that we created and create two new files 'Header.js' and 'Post.js'. Our folder structure should look like this:

![Folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z4urza3jrxmyf92kc4uh.png)

Our header component is quite simple, we have a title and a subtitle.

```
function Header() {
  return (
    <div className='header'>
        <h1>Read unlimited Memes <span>&#128512;</span></h1>
        <h3>Scroll down &#8595;</h3>
    </div>
  )
}
```

Here '&#128512' is the html entity for the emoji 😃 and '&#8595' is the html entity for &#8595;.


> Here is a tip. If you want to create a function component in vs code, you could use the shorthand 'rfce' by installing the reactjs code snippets extension. You can learn more about such shortcuts on the internet.

Now let's add some styling to the code.

```
.header {
  display: grid;
  place-items: center;
  text-align: center;
  padding: 40px;
}
```
Now our header component should look like this:

![Header component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/brcmx6sc7ic862n8utej.png)
You can make your own changes to the styling or you can keep it simple and minimal.

Now before we get into Post.js, we need to install axios and react-icons (it's not necessary).

```
npm install axios, react-icons
```
Inside Post.js, we will declare two components: Post and Card. Post component should look like this. (Don't forget to import the css files and axios)

```
function Post() {
    const [state, sestate] = React.useState();

    useEffect(() =>{
        axios.get(`https://meme-api.herokuapp.com/gimme/50`).then(response => {
            sestate(response.data.memes);
        }).catch(err => {
console.log(err)})
    }, [])

  return (
    <div className='post'>
        {state && state.map((meme, index) => {
            return <Card key={index} url={meme.url} name={meme.author}/>
        })}
    </div>
  )
}
```
Before we jump into the next section, you need to have a good understanding of [useState](https://reactjs.org/docs/hooks-state.html) and [useEffect](https://reactjs.org/docs/hooks-effect.html). So please do visit those links.

Here, inside the useEffect (to perform some actions before rendering a component), we set a state for the data returned by the API call. If you look at the api, you could see the that the url returns the URL for the image and 'author' give us the one who posted the meme. We send those data to the Card component as props.

Now let's create the card component. Here, we could display the data sent by the post component by {props.name} or {props.url}. Don't forget to add the parameter 'props' to the Card component

```
function Card(props){
    return(
        <div className='card'>
            <div className='frow trow'>
            <div className='name'>{props.name}</div>
            <div><FaEllipsisH style={{marginRight:'20px'}}/></div>
            </div>
            

            <div className='img'><img src={props.url} alt='Meme'/></div>
            <div className='frow'>
                <div className='lefticons'>
                    <FaHeart className='icon' size={40}/>
                    <FaComment className='icon' size={40}/>
                    <FaPaperPlane className='icon' size={40}/>
                </div>
                <div className='righticons'>
                    <FaBookmark className='icon2' size={40}/>
                </div>
            </div>
        </div>
    )
}
```

Please ignore the horrible classnames I have given, it's just for styling purposes.

Now, we have a working app, but you could only display 50 memes at a time. If you look at the documentation, you could see that maximum number of calls you could make is 50. 

axios.get(`https://meme-api.herokuapp.com/gimme/50`);

Here the 50 at the end represents no of memes required per call.

So we need the app to load more data when the user scrolls till end. So, How do we do that? First we need to modify our current useEffect function we have created.

```

    useEffect(() =>{

        window.addEventListener('scroll', handleScroll);

        axios.get(`https://meme-api.herokuapp.com/gimme/50`).then(response => {
            sestate(response.data.memes);
        }).catch(err => {
            console.log(err);
        })

        return () => window.removeEventListener('scroll', handleScroll);

    }, [])
```

We haven't created a function called 'hanldeScroll' yet, let's keep that for later. Then, we will create another useEffect function and declare another state, and will set it to false initially.

```
const [fetch, setfetch] = React.useState(false);
```

```
    useEffect(() =>{
        if (fetch){
            axios.get(`https://meme-api.herokuapp.com/gimme/50`).then(response => {
                sestate(prevState => [...prevState, ...response.data.memes]);
            })

    }, [fetch])
```

This useEffect will only be called when the state of the 'fetch' changes. The app won't work as we expected yet. but that's where the 'handleScroll' function comes in.

```
    function handleScroll() {
        if (window.innerHeight + document.documentElement.scrollTop +2 >= document.scrollingElement.scrollHeight) {
            // Do load more content here!
            setfetch(true)
        }
      }
```

What we are doing here is changing the state of 'fetch' to true when the user reaches the end of the window. When the state of the fetch changes, the above useEffect gets called and thus we can load more data to the state. 

We are not yet finished yet. Now we need some mechanism to change the state to false. so we use the settimeout function.

    useEffect(() =>{
        if (fetch){
            axios.get(`https://meme-api.herokuapp.com/gimme/50`).then(response => {
                sestate(prevState => [...prevState, ...response.data.memes]);
            })
            setTimeout(() =>{
                setfetch(false);
            },2000)            
        }

    }, [fetch])

I guess that's it. I have tried my absolute best to explain things. Please do give your feedback so that I could improve more. Thank you! Have a good day!