【Next.js】レイアウトを作っていく

components/Layout.js

import React, { Component } from 'react';
import Header from '../components/Header';
import Footer from '../components/Footer';
import style from '../static/Style';

class Layout extends Component {

    render() {
        return (<div>
            {style}
            <Header header={this.props.header}
                title={this.props.title} />
            {this.props.children}
            <Footer footer="copyright hogehoge."/>
        </div>)
    }
}
export default Layout;

components/Header.js

import React, {Component} from 'react';

class Header extends Component {
    render() {
        return (<header>
            <div>{this.props.header}</div>
            <h1>{this.props.title}</h1>
        </header>)
    }
}
export default Header;

components/Footer.js

import React, {Component} from 'react';

class Footer extends Component {
    render() {
        return (<footer>
            <div>{this.props.footer}</div>
        </footer>)
    }
}
export default Footer;

static/Style.js

export default <style>{`
    body {
        margin:10px;
        padding: 5px;
        color: #669;
    }
    header {
        font-size: 64pt;
        font-weight: bold;
        text-align:right;
        letter-spacing: -8px;
        color: #ddddff;
        margin: -32px 5px;
    }
    footer {
        color:#99c;
        font-size:12pt;
        text-align:right;
        border-bottom:1px solid #99c;
        margin: 50px 0px 10px 0px;
        position: relative;
        bottom: 10px;
        right: 10px;
        left: 10px;
    }
    h1 {
        font-size:68pt;
        font-weight:bold;
        text-align:right;
        letter-spacing:-8px;
        color:#f0f0f0;
        margin:-32px 0px;
    }
    p {
        margin:0px;
        color:#666;
        font-size:16pt;
    }
`}</style>

index.js

import Link from 'next/link';
import Layout from '../components/Layout';

export default () => (
    <Layout header="Next" title="Top page.">
        <p>Welcome to next.js!</p>
        <hr />
        <Link href="./other">
            <button>go to Other &gt;&gt;</button>
        </Link>
    </Layout>
);

other.js

import Link from 'next/link';
import Layout from '../components/Layout';


export default () => (
    <Layout header="Other" title="Other page.">
        <p>This is other page.</p>
        <hr />
        <Link href="./">
            <button>&lt;&lt; Back to Top</button>
        </Link>
    </Layout>
);

import React, { Component } from 'react';

class Image extends Component {
    constructor(props) {
        super(props);
        this.fname = "./static/" + props.fname;
        this.size = props.size + "px";
    }

    render() {
        return (
            <img width={this.size} border="1"
                src={this.fname} />
        );
    }
}
export default Image;

なるほど、面白いと言えば面白い。

【Next.js】基本的な使い方と特徴

– Next.jsはjsのみ。HTMLファイルは使わずに開発を行う
– Netx.jsでは、Reactとは異なり、複数ページ開発できる

{
    "scripts": {
        "dev": "next",
        "build": "next build",
        "start": "next start",
        "export": "next export"
    }
}

$ npm install –save next react react-dom

pages/index.js

export default () => <div>
    <h1>Next.js</h1>
    <div>Welcome to next.js!</div>
</div>

$ npm run dev

next.config.js

module.exports = {
    exportPathMap: function() {
        return {
            '/': {page: '/'}
        }
    }
}

$ npm run build

const h1 = {
    fontSize:'72pt',
    fontWeight:'bold',
    textAlign:'right',
    letterSpacing:'-8px',
    color:'#f0f0f0',
    margin:'-40px 0px'
}

const p = {
    margin:'0px',
    color:'#666',
    fontSize:'16pt'
}


export default () => <div>
    <h1 style={h1}>Next.js</h1>
    <p style={p}>Welcome to next.js!</p>
</div>

### 複数ページの開発
index.js

import Link from 'next/link';

const h1 = {
    fontSize:'72pt',
    fontWeight:'bold',
    textAlign:'right',
    letterSpacing:'-8px',
    color:'#f0f0f0',
    margin:'-40px 0px'
}

const p = {
    margin:'0px',
    color:'#666',
    fontSize:'16pt'
}


export default () => <div>
    <h1 style={h1}>Next.js</h1>
    <p style={p}>Welcome to next.js!</p>
    <hr />
    <div>
        <Link href="/other">
            Go to Other page &gt;&gt;
        </Link>
    </div>
</div>

other.js

import Link from 'next/link';

const h1 = {
    fontSize:'72pt',
    fontWeight:'bold',
    textAlign:'right',
    letterSpacing:'-8px',
    color:'#f0f0f0',
    margin:'-40px 0px'
}

const p = {
    margin:'0px',
    color:'#666',
    fontSize:'16pt'
}


export default () => <div>
    <h1 style={h1}>Next.js</h1>
    <p style={p}>This is Other page.</p>
    <hr />
    <div>
        <Link href="/">
            &lt;&lt;Back to Index page
        </Link>
    </div>
</div>

### Component
Counter.js

import React, { Component } from 'react';

export default class Counter extends Component {
    msgStyle = {
        fontSize:"16pt",
        backgroundColor:"#eef",
        padding:"5px"
    }

    constructor(props) {
        super(props);
        this.state = {
            counter:0,
            msg: 'counter: 0',
        };
        this.doAction = this.doAction.bind(this);
    }

    doAction() {
        this.setState((state) => {
            const num = state.counter + 1;
            return ({
                counter: num,
                msg: "counter: " + num
            });
        });
    }

    render() {
        return <p onClick={this.doAction}
            style={this.msgStyle}>
            {this.state.msg}
        </p>;
    }
}
import Counter from '../components/Counter';
import style from '../static/Style';

export default () => <div>
    {style}
    <h1>Next.js</h1>
    <p>Welcome to next.js!</p>
    <hr />
    <Counter />
</div>

Reactをより使いやすくした って感じやね

Next.js 入門

$ npm install -g pnpm
$ pnpm -v
10.6.5
$ npx create-next-app@latest nextjs-blog –use-pnpm
$ cd nextjs-blog
$ pnpm run dev

app/page.tsx

import Image from "next/image";

export default function Home() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <h1 className="text-4xl font-bold">Welcome!</h1>
      <p className="text-xl">This is where our journey begins!</p>
    </main>
  );
}
[/code

$ mkdir -p app/about
$ touch app/about/page.tsx

export default function About() {
    return (
      <div className="p-24">
        <h1 className="text-2xl font-bold mb-4">About My Blog</h1>
        <p>This blog app is designed to share insights and knowledge.</p>
      </div>
    );
  }

http://192.168.33.10:3000/about

appディレクトリで各ファイルが対応するURLに自動的にマッピングされる
publicは静的ファイル
next.config.jsはNext.jsの設定をカスタマイズ

export const posts = [
    {id: '1', title: '最初の投稿', content: 'これは最初の投稿です', author: 'Alice', createdAt: new Date('2025-01-01')},
    {id: '2', title: '2番目の投稿', content: 'これは2番目の投稿です', author: 'Bob', createdAt: new Date('2025-01-02')},
]
import Link from 'next/link';
import {posts} from '@/app/lib/placeholder-data';

export default function BlogList() {
    return (
        <div className="container mx-auto px-4 py-8">
            <h1 className="text-3xl font-bold mb-4">ブログ投稿一覧</h1>
            <ul className="space-y-4">
                {posts.map((post) => (
                    <li key={post.id} className="border p-4 rounded-lg">
                        <Link href={`/blog/${post.id}`} className="text-xl font-semibold text-blue-600 hover:underline">
                            {post.title}
                        </Link>
                        <p className="text-gray-600">{post.author} - {post.createdAt.toLocaleDateString()}</p>    
                    </li>
                ))}
            </ul>

        </div>
    );
}

なるほど、世界観は少しだけ理解しました^^