Memo

メモ > 技術 > フレームワーク: React.js

概要
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

Advertisement