1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

React(Tailwindcss + TypeScript)の構成でアプリを作成しました【Movie App】

Last updated at Posted at 2022-05-01

環境の準備

①ターミナルでreactアプリケーションを作成する。

$ npx create-react-app <プロジェクト名> --template typescript
% cd <プロジェクト名>
% yarn start

② 必要な環境を整える。

ESLintとPrettierとを基本からまとめてみた【React+TypeScriptのアプリにESLintとPrettierを導入】

$ npm i -D tailwindcss postcss autoprefixer
$ npm i tailwind-scrollbar-hide
$ npx tailwindcss init -p
$ yarn add axios
$ yarn add react-router-dom
$ yarn add react-paginate

③不要なファイルを削除する。

App.test.ts
logo.svg
reportWebVitals.ts
setupTests.ts

コンポーネント・ファイル構成

  src
   ├─ components
         ├── Movie.tsx
         └── Navbar.tsx
   ├── App.tsx
   ├── index.css
   └── index.tsx
├── .env
├── tailwind.config.ts
src/components/Movie.tsx

import React from 'react';

const IMG_API = 'https://image.tmdb.org/t/p/w1280';

type Props = {
  title: string;
  poster_path: string;
  overview: string;
};

const Movie: React.FC<Props> = ({ title, poster_path, overview }) => {
  return (
    <div className='.flex flex-wrap .m-3 w-80 relative group overflow-hidden'>
      <img
        className='max-w-full pt-10'
        src={IMG_API + poster_path}
        alt={title}
      />
      <div className='movie-info'>
        <h1 className='text-xl font-bold'> {title} </h1>
      </div>

      <div className='absolute bottom-0 left-0 right-0 p-4 text-white transition ease-in-out delay-300 translate-y-full bg-black group-hover:translate-y-0'>
        <h2 className='text-xl'>Overview</h2>
        <p>{overview}</p>
      </div>
    </div>
  );
};

export default Movie; 
src/components/NabBar.tsx
const NavBar: React.FC = () => {
  return (
    <div className='w-full'>
      <div className='text-white text-2xl font-bold md:text-4xl lg:text-5xl ml-4 pt-4'>
        Front-end Moivies App
      </div>
    </div>
  );
};

export default NavBar;
src/App.tsx
import { useEffect, useState } from 'react';
import Movie from './components/Movie';
import NavBar from './components/NavBar';
import axios from 'axios';
import loading_spinner from './assets/loading_spinner.gif';
import ReactPaginate from 'react-paginate';

async function getMovies(pageNo: number) {
  const res = await axios.get(
    `https://api.themoviedb.org/3/trending/movie/day?api_key=${process.env.REACT_APP_API_KEY}&page=${pageNo}`
  );
  console.log(res.data.results);
  return res.data.results;
}

function App() {
  const [movies, setMovies] = useState('Loading');
  const [pageNo, setPageNo] = useState(1);

  useEffect(() => {
    getMovies(pageNo)
      .then((res) => {
        setMovies(res);
      })
      .catch((err) => {
        alert(err);
      });
  }, [pageNo]);

  if (movies === 'Loading' || !movies || movies.length === 0)
    return (
      <div className='flex items-center justify-center h-screen bg-gray-200'>
        <img src={loading_spinner} alt='loading' height='200px' width='200px' />
      </div>
    );
  else
    return (
      <div className='flex flex-col h-full max-h-screen bg-black'>
        <NavBar />
        <div className='w-[250] mt-5 pb-10 font-bold pt-8'>
          <ReactPaginate
            previousLabel={'Previous'}
            nextLabel={'Next'}
            breakLabel={'...'}
            pageCount={1000}
            marginPagesDisplayed={3}
            pageRangeDisplayed={3}
            onPageChange={(e) => setPageNo(e.selected + 1)}
            containerClassName={
              'text-white justify-center items-center flex gap-x-5 gap-y-1.5'
            }
            pageClassName={
              'inline-flex justify-center items-center h-10 w-10 text-base font-bold bg-white rounded-full hover:border-black hover:font-bold '
            }
            pageLinkClassName={
              'inline-flex justify-center rounded-full align-middle text-black'
            }
            breakClassName={
              'inline-flex justify-center items-center h-10 w-10 text-base font-bold bg-white rounded-full'
            }
            breakLinkClassName={
              'inline-flex justify-center rounded-full align-middle text-black'
            }
            activeClassName={'bg-green-400'}
          />
        </div>
        <div className='box-border bg-black text-white font-sans .m-0 grid grid-cols-5 gap-5 items-center'>
          {movies.length > 0 &&
            Array.isArray(movies) &&
            movies.length > 0 &&
            movies.map((movie: any) => <Movie key={movie.id} {...movie} />)}
        </div>
      </div>
    );
}

export default App;
src/index.css
@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;

html {
  background-color: black;
}
.gitignore
//省略

.env //追加する
.env
REACT_APP_API_KEY= APIKEYを入力;
tailwind.config.js
module.exports = {
  content: ['./src/**/*.{tsx,ts}'],
  theme: {
    extend: {},
  },
  plugins: [require('tailwind-scrollbar-hide')],
};

参考サイト

Movies App - React Project
react-paginateを使用してページネーション用コンポーネントを作成する

React js Pagination With API Call Using React-paginate

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?