Skip to content

hiromichi-hayashi/next-todo

Repository files navigation

Next.jsとは?

Next.jsは、Vercel社によって開発されたReactベースのフロントエンドフレームワークです

Next.jsを使うことでReactだけではできないSSR/SG・headの変更・動的なルーティングなど を可能にします

特徴

Next.jsには、パフォーマンス、SEOやアプリケーション開発の効率化に関わる ルーティング, SSR・ SG(SSG), イメージに関する機能が事前に組み込まされています

・動的なルーティング

  Reactではプラグインを使用することでルーティングを可能にしていたが、   Next.jsではLinkコンポーネントを用いるだけでルーティングが使用でき、   getStaticPathsやgetStaticPropsを使用することでダイナミックルーティングなど、   動的なルーティングが可能になる

・SSRとSG

  Next.jsではReactではできなかったSG・SSRの切り替えができるようになり、   SPAだけでは難しかったSEO対策、パフォーマンスの向上が見込める

SG(SSG) とは... Static Generation の略で、 npm run build などビルドされるタイミングで、 依存関係にあるHTMLが事前に生成され、表示をより高速化することができる

SSRとは... Server side Renderingの略で、リクエストが起こる度に サーバ側でHTMLを生成され、 ページを常に最新状態に維持することができる

・画像の最適化

  Next.jsでは、Imageコンポーネントを使用することでブラウザが   サポートしている場合にはWebPのような最新の形式で画像をリサイズ、最適化ができる

Next.jsをセットアップしよう

※node環境が無い場合はあらかじめインストールしてください

  • 開発環境

 macOS Big Sur 11.6 (M1, 2020)  node 14.18.1  npm 6.14.15

・Next.jsのインストール

npx create-next-app@latest --ts
# or
yarn create next-app --typescript

npxまたはyarnでNext.jsのインストールをします

npx: 1個のパッケージを1.628秒でインストールしました。

? **What is your project named?** › 任意のプロジェクト名

作成するプロジェクト名を聞かれるので入力

cd 任意のプロジェクト名

インストールが完了したら任意のプロジェクトディレクトリに移動

npm run dev

コマンドを実行し、http://localhost:3000/でNext.jsのサイトが表示されれば環境構築成功です

nextjs.png

Next.jsでToDoアプリを作ってみよう

今回はNext.js+TypeScriptを使用して 簡単なToDoアプリを作成していきます

作成するディレクトリ構造は以下のようになります

pages
 ├── _app.tsx
 ├── componets
 │   ├── Form.tsx
 │   ├── Header.tsx
 │   ├── TodoContents.tsx
 │   └── index.tsx
 └── index.tsx
public
  └── img
      └── logo.png
styles
  ├── css
  │   └── reset.css
  └── sass
      ├── _config.scss
      └── style.module.scss

やること

  • ToDo項目の作成
  • ToDoの進捗状態のタスク切り替え

やらないこと

  • DBへの接続・保存
  • ToDoの編集
  • 動的なルーティング

1.スタイルの作成

今回はスタイルの説明を省略するため、GitHubから取得し、 Styelsとpublicに必要なファイルを追加、_app.tsxを以下のように書き直し、 reset.cssを適用してください

スタイルはこちら:GitHub

import type { AppProps } from "next/app";
import "../styles/css/reset.css";

function MyApp({ Component, pageProps }: AppProps) {
	return <Component {...pageProps} />;
}

export default MyApp;

また、sassを使用しているためインストールしてください

npm install sass

2.ToDoアプリのコンポーネントを作成

ToDoアプリに必要な機能をHeader.tsx, TodoContents.tsx, Form.tsxの 3つのコンポーネントに分けて作成していきます

まず、Header.tsxを作成します

import Link from "next/link";
import Image from "next/image";
import logo from "../../public/img/logo.png";
import styles from "../../styles/sass/style.module.scss";

const Header = () => {
	return (
		<>
			<header className={styles.header}>
				<Link href="/">
					<a className={styles.header_logo}>
						<Image src={logo} alt="LOGO" />
					</a>
				</Link>
			</header>
		</>
	);
};

export default Header;

Next.jsではLinkコンポーネントを使用することでルーティングを実現できます 使用方法もLinkコンポーネントをインポートしてくるだけなのでとても簡単です

import Link from "next/link";

ロゴ部分はImageコンポーネントを使用することで可読性が良くなります

また、画像拡張子をWebPなどの最適な拡張子に自動で変換されるため、 表示速度が格段に上がります

/*imgタグの書き方*/
<img src="./assets/img/logo.png" alt="LOGO">


/*Imageコンポーネントの書き方*/
import Image from "next/image";
import logo from "../../public/img/logo.png";

<Image src={logo} alt="LOGO" />

次にTodoContents.tsxを作成します

このコンポーネントでは、ToDoの一覧機能、絞り込み機能を作成していきます

Formコンポーネントから受け取る値を配列にしているため、 一覧機能、絞り込み機能は配列を操作するメソッドを使用して実装しています

import { useState } from "react";
import Form from "./Form";
import styles from "../../styles/sass/style.module.scss";

const TextContents = () => {
	const [todos, setTodos] = useState([]);
	const [todoStatus, setTodoStatus] = useState("全て");
	
	const todoProcess = ["全て", "完了", "未完了"];

	//Formコンポーネントから渡された値を格納していく
	const getTodo = (id, todo, status) => {
		setTodos([...todos, {id, todo, status }]);
	};

	//完了・未完了の場合のTodoをソートする
	const filterTodos = () => {
		if (todoStatus === "完了") {
			const completeTodos = todos.filter(value => value.status === true);

			return completeTodos;
		}else if (todoStatus === "未完了") {
			const incompleteTodos = todos.filter(value => value.status === false);

			return incompleteTodos;
		}

		return todos;
	};

	//Todoが完了・未完了かを切り替える
	const isTodoChangeStatus = (id) => {
		const changeStatus = todos.map( index => {
			if (index.id === id) {
				index.status = !index.status ;
			}
			return index;
		})

		setTodos(changeStatus)
	};

	return (
		<main>
			<Form addTodo={getTodo}/>
			<div className={styles.contents}>
				<div className={styles.contents_tabs}>
					{todoProcess.map((status, index) => {
						return (
							<button 
								className={`${styles.contents_tabs_tab} ${todoStatus === status && styles.is_active}`}
								key={index}
								onClick={() => setTodoStatus(status)}>
									{status}
							</button>
						)
					})}
				</div>
				{filterTodos().map((value, index) => {
					return (
						<li className={styles.list_item} key={index}>
							<p className={`${styles.list_item_ttl} ${value.status && styles.is_done_item_ttl}`}>
							  {value.todo}
							</p>
							<button
							  className={`${styles.list_item_button} ${value.status && styles.is_done_item_button}`} 
							  onClick={() => isTodoChangeStatus(value.id)}>
								完了
							</button>
						</li>
					)
				})}
			</div>
		</main>
	);
};

export default TextContents;

ソート機能はfilterメソッドを使い指定された配列からコールバック関数の条件に該当する 要素を持つ新しい配列を作成します

const filterTodos = () => {

        if (todoStatus === "完了") {
            //この場合はtodosのstatusがtureのものだけ取得する
            const completeTodos = todos.filter(value => value.status === true);            
            return completeTodos;
        }else if (todoStatus === "未完了") {
            //この場合はtodosのstatusがfalseのものだけ取得する
            const incompleteTodos = todos.filter(value => value.status === false);
            return incompleteTodos;
        }
        
        return todos;
    };

一覧機能はmapメソッドを使い指定された配列要素を1個ずつ呼び出し 新しい配列としてreturnの形で返します

{filterTodos().map((value, index) => {
     return (
       <li className={styles.list_item} key={index}>
          <p className={`${styles.list_item_ttl} ${value.status && styles.is_done_item_ttl}`}>
             {value.todo}
          </p>
          <button 
            className={`${styles.list_item_button} ${value.status && styles.is_done_item_button}`} 
            onClick={() => isTodoChangeStatus(value.id)}>
            完了
           </button>
        </li>
      )
 })}

TodoContents.tsxで扱うForm.tsxを作成していきます

Form.tsxではユニークIDをuuid.jsを使い作成するのでインストールします

npm install uuid

TodoContents.tsxからpropsで渡ってきたgetTodo関数にsetTodoを渡します その際、ユニークidをuuid()で作成します

追加ボタンには空欄で追加できないよう、アラート表示をします

import { useState } from "react";
import { v4 as uuidv4 } from 'uuid';
import styles from "../../styles/sass/style.module.scss";

const Form = (props) => {
	const [text, setText] = useState("");

	const submitText = () => {
	    if (text === "") {
	 		alert("Todoを入力してください");
			return;
		}

        props.addTodo(uuidv4(), text, false);
		setText("");
     }

	return (
		<form className={styles.form}>
			<input
				className={styles.form_txt}
				type="text"
				placeholder="TODO"
				value={text}
				onChange={e => setText(e.target.value)}
			/>
			<button className={styles.form_submit} type="button" onClick={submitText}>
				追加
			</button>
		</form>
	);
};

export default Form;

3.Todoアプリを画面に表示する

必要なコンポーネントは作成できたのでindex.tsxに追加していきます

ここで使用しているHeadコンポーネントはSEO対策をする際に重要になってくる メタデータやタイトルを各ページごとに設定することができるようになります

詳しくは公式ドキュメント:next/head

import Head from "next/head";
import Header from "./componets/Header";
import TodoContents from "./componets/TodoContents";

const App = () => {

	return (
		<>
			<Head>
				<link rel="stylesheet" href="./assets/css/reset.css" />
				<title>Next.js-ToDo</title>
				<meta charSet="utf-8" />
				<meta http-equiv="X-UA-Compatible" content="IE=edge" />
				<meta name="viewport" content="width=device-width, initial-scale=1" />
			</Head>
			<Header />
			<TodoContents/>
		</>
	);
};

export default App;

これでToDoアプリが作成できたので画面に表示させてみましょう

npm run dev

コマンドを実行後、http://localhost:3000/でToDo画面が表示せれれば完成です お疲れ様でした

スクリーンショット 2021-12-06 1.04.48.png

Next.js 使ったみた感想

元々Reactを使ったことがありNext.jsは知っていましたが実際に勉強してみると プラグインで使っていた機能が標準で備わっていたりしたので、Reactに触れてから Next.jsに取り組めば恩恵を感じられると思います

今回のToDoアプリでは使用しなかった動的ルーティング、画像のサイズや拡張子の最適化など Next.jsには便利な機能が多いので興味があれば勉強してみてください

参考サイト Next.js公式 Next.js 10 の新機能 next/image のオプション全部触ってみる Next.jsのルーティング

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published