概要
React - ユーザインターフェース構築のための JavaScript ライブラリ
https://ja.reactjs.org/
React入門 - とほほのWWW入門
http://www.tohoho-web.com/ex/react.html
jQueryを卒業したかった僕がReact StaticでReactをイチから学んでWebサイトを作った話 | 株式会社ヌーラボ(Nulab inc.)
https://nulab.com/ja/blog/typetalk/how-to-make-website-with-react-static/
Reactベストプラクティスの宝庫!「bulletproof-react」が勉強になりすぎる件
https://zenn.dev/meijin/articles/bulletproof-react-is-best-architecture
React + Typescript の現場で初心者からよくあった質問とか小技的なのを書いてく - Qiita
https://qiita.com/dosukoi_man/items/70386fa0bb919804eaed
React フレームワークの 動向と選定基準 - Speaker Deck
https://speakerdeck.com/azukiazusa1/react-huremuwakuno-dong-xiang-toxuan-ding-ji-zhun
Reactで使用するJSXの基本をわかりやすく解説|Kinsta
https://kinsta.com/jp/knowledgebase/what-is-jsx/
ReactとVue.jsはどっちがいい?それぞれの特徴や違い…|Udemy メディア
https://udemy.benesse.co.jp/development/system/react-vue.html
【完全版】これ1本でReactの基本がマスターできる!初心者チュートリアル! #TypeScript - Qiita
https://qiita.com/Sicut_study/items/d520f9a858506b81e874
Rules of React を経典に React を書いて心の安寧を保つべし #JavaScript - Qiita
https://qiita.com/tomada/items/91bd4ffcb601cf3b85d7
簡易な開発
■ReactをCDNで利用
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>React</title>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
</head>
<body>
<h1>React</h1>
<div id="root">
<p>Loading...</p>
</div>
<script>
let dom = document.querySelector('#root');
let element = React.createElement(
'p', {}, 'Hello Rect!',
);
ReactDOM.render(element, dom);
</script>
</body>
</html>
なお、上記で読み込んでいるscriptは開発用のもの。
本番環境では、以下のように圧縮されたファイルを読み込むといい。
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
↓
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
■開発ツールスタンドアロン版
>npm install -g react-devtools
>react-devtools
以下のようなGUI画面が表示される。
Add one of the following (click to copy).
<script src="http://localhost:8097"></script>
<script src="http://192.168.56.1:8097"></script>
to the top of the page you want to debug,
before importing React DOM.
作成したファイル内 <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script> の直前に以下を追加する。
<script src="http://localhost:8097"></script>
その後GUI画面を確認すると、開発ツールが表示されている。
コマンドプロンプトで終了すると、開発ツールが終了される。
プロジェクトを作成して開発
■プロジェクトを作成
>cd C:\path\to\react_project
>npx create-react-app react_app
react_app フォルダが作成され、その中にファイルが作成される。
なおプロジェクトは、npx ではなく以下のように npm でも作成できる。結果は同じ。
npm は「パッケージをインストールして実行」となるが、
npx は「パッケージを一時的にダウンロードして実行し、完了したらパッケージをクリア」となる。
ダウンロードのための時間はかかるが、ローカル環境にパッケージをインストールしないで済むため、
現在は npx によるプロジェクト作成が主流となっている。
>npm init react-app react_app
プロジェクトの操作はこのフォルダ内で行うため、フォルダ内に移動しておく。
>cd react_app
以下でプロジェクトを実行する。
>npm start
Compiled successfully!
You can now view react_app in the browser.
Local: http://localhost:3000
On Your Network: http://172.23.144.1:3000
Note that the development build is not optimized.
To create a production build, use npm run build.
webpack compiled successfully
上記のように表示され、表示されている http://localhost:3000 にアクセスするとページが表示される。
■プロジェクトをビルド
以下でプロジェクトをビルドできる。
>npm run build
build フォルダが作成され、その中にファイルが書き出さる。
これらをWebサーバの公開フォルダ直下に配置すると画面が表示される。
パスは「/」はじまりのため、公開フォルダ直下でないと表示されないが、
package.json に以下を追加して再ビルドすると表示されるようになる。
{
"name": "react_app",
"version": "0.1.0",
"private": true,
"homepage": "./", … 追加。
JSX
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>React</title>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<h1>React</h1>
<div id="root">
<p>Loading...</p>
</div>
<script type="text/babel">
let dom = document.querySelector('#root');
let element = (
<div>
<h2>JSX Sample</h2>
<p>これはJSXのサンプルです。</p>
</div>
);
ReactDOM.render(element, dom);
</script>
</body>
</html>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> を読み込むと、
<script type="text/babel"></script> 内にJSXを記述することができる。
■値を埋め込む
<div id="root">
<p>Loading...</p>
</div>
<script type="text/babel">
let dom = document.querySelector('#root');
let title = 'タイトル';
let message = 'メッセージ。';
let message_style = {
fontSize: "20px",
color: "#FF0000",
border: "1px solid #000000"
};
let link = 'https://www.google.co.jp/';
let element = (
<div>
<h2>{title}</h2>
<p style={message_style}>{message}</p>
<p><a href={link}>リンク</a></p>
</div>
);
ReactDOM.render(element, dom);
</script>
「{」と「}」で囲うと変数を埋め込める。
変数の値を属性に使う場合、ダブルクォートは不要。
■関数でJSXを作る
<div id="root">
<p>Loading...</p>
</div>
<script type="text/babel">
let dom = document.querySelector('#root');
let printMsg = function(message, size, color) {
let style = {
fontSize: size + "px",
color: color,
border: "1px solid #000000"
};
return <p style={style}>{message}</p>;
}
let element = (
<div>
<h2>関数でJSXを作る</h2>
<ul>
<li>{printMsg('メッセージ1', 10, '#FF0000')}</li>
<li>{printMsg('メッセージ2', 20, '#00FF00')}</li>
<li>{printMsg('メッセージ3', 30, '#0000FF')}</li>
</ul>
</div>
);
ReactDOM.render(element, dom);
</script>
■配列を扱う
<div id="root">
<p>Loading...</p>
</div>
<script type="text/babel">
let dom = document.querySelector('#root');
let data = [
<li>太郎</li>,
<li>花子</li>,
<li>幸子</li>
];
let element = (
<div>
<h2>配列を扱う</h2>
<ul>
{data}
</ul>
</div>
);
ReactDOM.render(element, dom);
</script>
■mapで配列を扱う
<div id="root">
<p>Loading...</p>
</div>
<script type="text/babel">
let dom = document.querySelector('#root');
let data = [
{ name: '太郎', mail: 'taro@example.com', age: 45 },
{ name: '花子', mail: 'hanako@example.com', age: 37 },
{ name: '幸子', mail: 'sachiko@example.com', age: 29 }
];
let element = (
<div>
<h2>mapで配列を扱う</h2>
<table border="1">
<tr>
<th>name</th>
<th>mail</th>
<th>age</th>
</tr>
{data.map((value) => (
<tr>
<td>{value.name}</td>
<td>{value.mail}</td>
<td>{value.age}</td>
</tr>
))}
</table>
</div>
);
ReactDOM.render(element, dom);
</script>
■表示を更新する
<div id="root">
<p>Loading...</p>
</div>
<script type="text/babel">
let dom = document.querySelector('#root');
let p_style = {
fontSize: "20px"
};
var counter = 0;
setInterval(() => {
counter++;
let element = (
<div>
<p style={p_style}>count: {counter}</p>
</div>
);
ReactDOM.render(element, dom);
}, 1000);
</script>
■フォームの値を利用する
<div id="root">
<p>Loading...</p>
</div>
<script type="text/babel">
let dom = document.querySelector('#root');
let p_style = {
fontSize: "20px"
};
let message = 'お名前を入力してください。';
let name = '';
let doChange = (event) => {
name = event.target.value;
message = 'こんにちは、' + name + 'さん。';
};
let doAction = (event) => {
let element = (
<div>
<p style={p_style}>{message}</p>
<div>
<input type="text" id="name" onChange={doChange} />
<button onClick={doAction}>Click</button>
</div>
</div>
);
ReactDOM.render(element, dom);
};
doAction();
</script>
コンポーネント
■関数コンポーネントを使う
<div id="root">
<p>Loading...</p>
</div>
<script type="text/babel">
let dom = document.querySelector('#root');
// 関数コンポーネント
function Hello() {
return <p>Hello! React</p>
}
let element = (
<div>
<h2>JSX Sample</h2>
<Hello />
</div>
);
ReactDOM.render(element, dom);
</script>
■関数コンポーネントで属性を利用する
<div id="root">
<p>Loading...</p>
</div>
<script type="text/babel">
let dom = document.querySelector('#root');
// 関数コンポーネント
function Hello(props) {
return <p>{props.name}さん、{props.greeting}。</p>
}
let element = (
<div>
<h2>JSX Sample</h2>
<Hello name="太郎" greeting="こんにちは" />
<Hello name="花子" greeting="こんばんは" />
</div>
);
ReactDOM.render(element, dom);
</script>
■コンポーネントをクラスで作成する
<div id="root">
<p>Loading...</p>
</div>
<script type="text/babel">
let dom = document.querySelector('#root');
// コンポーネントをクラスで作成
class Hello extends React.Component {
name = '';
greeting = '';
constructor(props) {
super(props);
this.name = props.name;
this.greeting = props.greeting;
}
render() {
return <p>{this.name}さん、{this.greeting}。</p>;
}
}
let element = (
<div>
<h2>JSX Sample</h2>
<Hello name="太郎" greeting="こんにちは" />
<Hello name="花子" greeting="こんばんは" />
</div>
);
ReactDOM.render(element, dom);
</script>
関数コンポーネント
シンプルな関数コンポーネント。
import './App.css';
function App() {
return (
<div className="App">
<h1>React</h1>
<p>これはサンプルのコンポーネントです。</p>
</div>
);
}
export default App;
■ステート
以下はクリックしてもカウントアップされない。
関数コンポーネントは、「呼び出されたときだけ働き、描画し終えたら消えるもの」のため。
import './App.css';
function App() {
var counter = 0;
const doClick = ()=> {
counter++;
}
return (
<div className="App">
<h1>React</h1>
<p>これはサンプルのコンポーネントです。</p>
<p onClick={doClick}>counter: {counter}</p>
</div>
);
}
export default App;
以下のように、ステートを使うと値を保持できる。
「import { useState } from 'react';」で関数を読み込み、「const [値を保持する変数名, 値を変更する関数名] = useState(値の初期値);」のように使用する。
値が更新されると、表示も自動で更新される。
import './App.css';
import { useState } from 'react';
function App() {
const [counter, setCounter] = useState(0);
const doClick = ()=> {
setCounter(counter + 1);
}
return (
<div className="App">
<h1>React</h1>
<p>これはサンプルのコンポーネントです。</p>
<p onClick={doClick}>counter: {counter}</p>
</div>
);
}
export default App;
以下のようにして、フォームの値をもとに表示を更新できる。
import './App.css';
import { useState } from 'react';
function App() {
const [name, setName] = useState('');
const [message, setMessage] = useState('名前を入力してください。');
const doInput = (e)=> {
setName(e.target.value);
}
const doClick = (e)=> {
e.preventDefault();
setMessage('こんにちは、' + name + 'さん。');
}
return (
<div className="App">
<h1>React</h1>
<p>{message}</p>
<form>
<input type="text" onChange={doInput} />
<button onClick={doClick}>クリック</button>
</form>
</div>
);
}
export default App;
以下のように、副作用フックを使うとコンポーネントの更新時に自動で処理を実行できる。
「import { useState, useEffect } from 'react';」で関数を読み込み、「useEffect(() => { 実行させたい処理 }, [更新を監視する変数]);」のように使用する。
import './App.css';
import { useState, useEffect } from 'react';
function App() {
const [number, setNumber] = useState(0);
const [message, setMessage] = useState('');
const doInput = (e)=> {
setNumber(e.target.value);
}
useEffect(() => {
if (number < 2) {
setMessage('1より大きい自然数を入力してください。');
} else {
var prime = true;
for (var i = 2; i <= number / 2; i++) {
if (number % i === 0) {
prime = false;
break;
}
}
setMessage(prime ? '素数です。' : '素数ではありません。');
}
}, [number]);
return (
<div className="App">
<h1>React</h1>
<p>{message}</p>
<form>
<input type="text" onChange={doInput} />
</form>
</div>
);
}
export default App;
クラスコンポーネント(以前に検証したもの)
>cd C:\path\to\react_project
>npm init react-app react_app
>cd react_app
>npm start
http://localhost:3000/ にアクセスするとページが表示される。
これをベースに試していく。
主なファイルは以下のとおり。
メインの画面となるHTML。
public\index.html
メインの処理となるJavaScript。
src\index.js
CSS。
src\index.css
実際に画面に表示を行うコンポーネント。
src\App.js
src\App.js を編集して画面表示を変更してみる。
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>これはサンプルのコンポーネントです。</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
編集してファイルを保存すると、自動で http://localhost:3000/ の内容が更新される。
■HTMLとCSSの編集
src\App.js
import React from 'react';
import './App.css';
function App() {
return (
<div>
<h1>React</h1>
<p>This is sample component.</p>
<p>これはサンプルのコンポーネントです。</p>
</div>
);
}
export default App;
src\App.css
body {
margin: 20px;
}
h1 {
font-size: 72pt;
font-weight: bold;
text-align: right;
letter-spacing: -8px;
color: #eee;
margin: -40px 0;
}
p {
margin: 0;
color: #666;
font-size: 16pt;
}
■コンポーネントを組み合わせる
src\App.js
import React from 'react';
import './App.css';
function App() {
return (
<div>
<h1>React</h1>
<p>This is sample component.</p>
<p>これはサンプルのコンポーネントです。</p>
<Rect x="50" y="250" width="150" height="150" color="#AAF" />
<Rect x="180" y="150" width="120" height="120" color="#FAA" />
</div>
);
}
class Rect extends React.Component {
x = 0;
y = 0;
width: 0;
height: 0;
color: '#000';
style = {};
constructor(props) {
super(props);
this.x = props.x;
this.y = props.y;
this.width = props.width;
this.height = props.height;
this.color = props.color;
this.style = {
backgroundColor: this.color,
position: "absolute",
left: this.x + "px",
top: this.y + "px",
width: this.width + "px",
height: this.height + "px"
};
}
render() {
return <div style={this.style}></div>;
}
}
export default App;
■コンポーネントを別ファイルにする
src\App.js
import React from 'react';
import Rect from './Rect';
import './App.css';
function App() {
return (
<div>
<h1>React</h1>
<p>This is sample component.</p>
<p>これはサンプルのコンポーネントです。</p>
<Rect x="50" y="250" width="150" height="150" color="#AAF" />
<Rect x="180" y="150" width="120" height="120" color="#FAA" />
</div>
);
}
export default App;
src\Rect.js
import React from 'react';
class Rect extends React.Component {
x = 0;
y = 0;
width: 0;
height: 0;
color: '#000';
style = {};
constructor(props) {
super(props);
this.x = props.x;
this.y = props.y;
this.width = props.width;
this.height = props.height;
this.color = props.color;
this.style = {
backgroundColor: this.color,
position: "absolute",
left: this.x + "px",
top: this.y + "px",
width: this.width + "px",
height: this.height + "px"
};
}
render() {
return <div style={this.style}></div>;
}
}
export default Rect;
■ステートを使う
・プロパティ … クラスに値を保管しておくもの。
・props … コンポーネントの属性を保管しておくもの。読み出し専用。
・ステート(state) … コンポーネントの状態を保管しておくもの。コンポーネントの表示を変えたりするときに使う。
src\App.js
import React from 'react';
import './App.css';
class App extends React.Component {
msgStyle = {
color: "#666"
};
alertStyle = {
color: "#C00",
fontWeight: "bold"
};
btnStyle = {
fontWeight: "bold"
};
constructor(props) {
super(props);
this.state = {
counter: 1,
msg: 'count start!'
};
this.doAction = this.doAction.bind(this); // イベントで実行できるようにする
}
doAction(e) {
this.setState((state) => ({
counter: state.counter + 1,
msg: 'count: ' + state.counter,
flg: state.counter % 5 == 0 // 数値によってフラグを設定する
}));
}
render() {
return (
<div>
<h1>React</h1>
{this.state.flg ? // フラグによって表示を切り替える
<p style={this.alertStyle}>{this.state.msg}</p>
:
<p style={this.msgStyle}>{this.state.msg}</p>
}
<button style={this.btnStyle} onClick={this.doAction}>クリック</button>
</div>
);
}
}
export default App;
■子エレメントを取得する
src\App.js
import React from 'react';
import './App.css';
function App() {
return (
<div>
<h1>React</h1>
<Message title="Children!">
これは/テスト/です。
</Message>
</div>
);
}
class Message extends React.Component {
render() {
let children = this.props.children.split('/');
let list = [];
for (let i = 0; i < children.length; i++) {
if (children[i].trim() != '') {
list.push(
<li>{children[i]}</li>
);
}
}
return (
<div>
<h2>{this.props.title}</h2>
<ul>{list}</ul>
</div>
);
}
}
export default App;
■フォームを利用する
src\App.js
import React from 'react';
import './App.css';
class App extends React.Component {
msgStyle = {
color: "#666"
};
btnStyle = {
fontWeight: "bold"
};
constructor(props) {
super(props);
this.state = {
message: '名前を入力してください。'
};
this.doChange = this.doChange.bind(this); // イベントで実行できるようにする
this.doSubmit = this.doSubmit.bind(this); // イベントで実行できるようにする
}
doChange(event) {
this.input = event.target.value;
}
doSubmit(event) {
this.setState({
message: 'こんにちは!' + this.input + 'さん。'
});
event.preventDefault();
}
render() {
return (
<div>
<h1>React</h1>
<p style={this.msgStyle}>{this.state.message}</p>
<form onSubmit={this.doSubmit}>
<label>
<input type="text" onChange={this.doChange} />
</label>
<input type="submit" style={this.btnStyle} />
</form>
</div>
);
}
}
export default App;
React Router
2022年中にreact-router-domの理解を深めたい #React - Qiita
https://qiita.com/TMDM/items/0939ff52ab5b459303d7
React Router でルーティングを管理しよう(初心者向け) | Muscle Coding
https://musclecoding.com/react-router/
React Routerのルーティング実装
https://zenn.dev/takaya39/articles/4669c3fd1c7f04
■準備
今回は「プロジェクトを作成して開発」で作成したプロジェクトを使用する。
>cd C:\path\to\react_app
>npm install react-router-dom
>npm start
src/App.js の内容を以下のようにし、ページにアクセスして「react-router」と表示されることを確認する。
function App() {
return (
<div>
<h1>react-router</h1>
</div>
);
}
export default App;
■ルーティングの確認
以下のファイルを作成する。
src/routes/Home.js
import { Link } from "react-router-dom";
export const Home = () =>{
return (
<div>
<p>Home</p>
<ul>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</div>
)
}
src/routes/About.js
import { Link } from "react-router-dom";
export const About = () =>{
return (
<div>
<p>About</p>
<ul>
<li><Link to="/">Home</Link></li>
</ul>
</div>
)
}
src/routes/Contact.js
import { Link } from "react-router-dom";
export const Contact = () =>{
return (
<div>
<p>Contact</p>
<ul>
<li><Link to="/">Home</Link></li>
</ul>
</div>
)
}
src/routes/Notfound.js
import { Link } from "react-router-dom";
export const Notfound = () =>{
return (
<div>
<p>Notfound</p>
<ul>
<li><Link to="/">Home</Link></li>
</ul>
</div>
)
}
以下のファイルを編集する。
src/App.js
import { Routes, Route } from "react-router-dom";
import { Home } from "./routes/Home";
import { About } from "./routes/About";
import { Contact } from "./routes/Contact";
import { Notfound } from "./routes/Notfound";
function App () {
return (
<div>
<h1>react-router</h1>
<Routes>
<Route path="/" element={ <Home /> } />
<Route path="/about" element={ <About /> } />
<Route path="/contact" element={ <Contact /> } />
<Route path="*" element={ <Notfound /> } />
</Routes>
</div>
);
}
export default App;
src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
これで http://localhost:3000/ にアクセスすると、Homeの画面が表示される。
各リンクからAboutやContactに遷移でき、URLも変化する。
存在しないURLにアクセスされた場合、Notfoundの画面が表示される。
■データの取得
以下が参考になるか。
React Router v6のルーティング方法を解説 - createBrowserRouterとData APIsの活用法 | DevelopersIO
https://dev.classmethod.jp/articles/react-router-v6-4-createbrowserrouter-data-apis/
以下は参考記事のメモ。
Laravel x Inertia.js 現代のモノリス によるお手軽 SPA 開発 - Speaker Deck
https://speakerdeck.com/tutida/laravel-x-inertia-dot-js-xian-dai-nomonorisu-niyoruoshou-qing-spa-kai...
以下はChatGPTによるコード。
src/routes/Home.js
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
export const Home = () => {
const [posts, setPosts] = useState([]);
const [error, setError] = useState(null);
// 外部データを取得するための useEffect フック
useEffect(() => {
const fetchPosts = async () => {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=5");
if (!response.ok) {
throw new Error(`Error: ${response.statusText}`);
}
const data = await response.json();
setPosts(data);
} catch (err) {
setError(err.message);
}
};
fetchPosts();
}, []); // 空の依存配列により、コンポーネントがマウントされたときのみ実行
return (
<div>
<p>Home</p>
<ul>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
<h2>Posts</h2>
{error ? (
<p style={{ color: "red" }}>Failed to fetch posts: {error}</p>
) : posts.length > 0 ? (
<ul>
{posts.map((post) => (
<li key={post.id}>
{post.id}: {post.title}
</li>
))}
</ul>
) : (
<p>Loading...</p>
)}
</div>
);
};
■データの投稿
以下はChatGPTによるコード。
import { Link, useNavigate } from "react-router-dom";
import { useState } from "react";
export const Home = () => {
const [title, setTitle] = useState("");
const [body, setBody] = useState("");
//const navigate = useNavigate(); // 投稿後にリダイレクトさせる場合
const handleSubmit = async (e) => {
e.preventDefault();
try {
// POSTリクエストを送信
const response = await fetch("http://localhost/~test/react/post/post.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({ title, body }).toString(),
});
if (response.ok) {
console.log("データが正常に送信されました");
} else {
console.error("データ送信に失敗しました", response.statusText);
}
} catch (error) {
console.error("エラーが発生しました", error);
}
console.log("Title:", title);
console.log("Body:", body);
//navigate("/complete"); // 投稿後にリダイレクトさせる場合
};
return (
<div>
<p>Home</p>
<ul>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
<form onSubmit={handleSubmit}>
<dl className="mb-2">
<dt>タイトル</dt>
<dd><input type="text" name="title" value={title} onChange={(e) => setTitle(e.target.value)} className="border-2 p-1 block w-64" /></dd>
<dt>本文</dt>
<dd><textarea name="body" value={body} onChange={(e) => setBody(e.target.value)} className="border-2 p-1 block w-64 h-28" /></dd>
</dl>
<p>
<button type="submit" className="border-2 p-2">作成</button>
</p>
</form>
</div>
);
};
post.php の内容は以下のとおり。
同じ階層に post.log があり、そこに投稿データが記録される。
<?php
header('Access-Control-Allow-Origin: http://localhost:3000'); // フロントエンドのオリジンを許可
header('Access-Control-Allow-Methods: POST'); // 許可するHTTPメソッド
header('Access-Control-Allow-Headers: Content-Type'); // 許可するヘッダー
$title = $_POST['title'];
$body = $_POST['body'];
if (file_put_contents('post.log', "title=" . $title . "\nbody=" . $body . "\n") === false) {
exit('NG');
}
echo 'OK';
「Access-Control-Allow-Origin」などについては以下を参照
なんとなく CORS がわかる...はもう終わりにする。 #JavaScript - Qiita
https://qiita.com/att55/items/2154a8aad8bf1409db2b
引き続き
React 研修 (2024) - Speaker Deck
https://speakerdeck.com/recruitengineers/react-yan-xiu-2024
React Hook Formの基本を理解してフォームを作成してみよう | アールエフェクト
https://reffect.co.jp/react/react-hook-form
React-Hook-Formのおさらい
https://zenn.dev/kagunyan25/articles/0d0437a1c30867
Reactを取り巻く状態管理の潮流を学ぼう。HooksやServer Componentsなどの登場で何が変わるか - エンジニアHub|Webエンジニアのキャリアを考える!
https://eh-career.com/engineerhub/entry/2022/01/13/090000
【React】なぜコンポーネントの中でコンポーネントを作るのは良くないのか?
https://zenn.dev/dinii/articles/7eba16ed5513c1
React Queryはデータフェッチライブラリではない。非同期の状態管理ライブラリだ。 #TypeScript - Qiita
https://qiita.com/taisei-13046/items/05cac3a2b4daeced64aa