Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
React x Socket.ioで人狼サーバを作る 第一章 フロントエンド実装
Search
Ryosuke Uchiyama
February 11, 2022
Technology
35
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
React x Socket.ioで人狼サーバを作る 第一章 フロントエンド実装
Ryosuke Uchiyama
February 11, 2022
More Decks by Ryosuke Uchiyama
See All by Ryosuke Uchiyama
AWSでサーバレスな書籍管理アプリを作る
step63r
0
69
PythonでSlack通知botを作る
step63r
0
23
ChatGPT実践
step63r
1
400
IoT実践! 行先予定表を電子ペーパーで作る
step63r
0
50
深層強化学習で東方AI 第一章 DQNの基本
step63r
0
390
Build 2021 プレイバック
step63r
0
44
WPFで実践アプリ開発! 第四章 機能の実装 Part 2
step63r
0
62
WPFで実践アプリ開発! 第三章 機能の実装 Part 1
step63r
0
140
WPFで実践アプリ開発! 第二章 UI
step63r
0
190
Other Decks in Technology
See All in Technology
OpenClawでAzure DevOpsのWiki更新を自動化する - クラウドAIだけでは届かない場所へ
yutakaosada
0
130
SQL Server 2025 最適化されたロック
odashinsuke
0
100
Apache Iceberg が拓く AI 時代のオープンレイクハウス
tomtanaka
0
200
音声コミュニティを守るAI監視基盤_ 90%以上の入力削減を支えたServerless設計と運用判断
shuheioka123
0
120
AIエージェントを安全で速い現場監督にする:Jev・Obsidian・メタハーネス
x5gtrn
PRO
0
140
AWS FinOps Agent 結局何が得意なの?
siromi
0
220
The kernel report
ennael
PRO
1
160
React Nativeでの OTA Updateって、 どう説明する?
ichiki1023
0
130
あなたの知らないAmazon VPC Route Server/Amazon VPC Route Server you don't know about
masakiokuda
0
170
Swap and Memory Reclaim - Squeezing Out More RAM
ennael
PRO
1
1.4k
可視化から始めたAI駆動開発_ochi_ver1.01 / AI-Driven Development Starting with Visualization_ver1.01
yayoi_dd
0
110
全社共通データ基盤をつくる。ソニーのDatabricks活用とデータガバナンス設計の裏側
sony
0
260
Featured
See All Featured
Building Adaptive Systems
keathley
44
3.2k
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
440
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
250
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
840
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
Claude Code のすすめ
schroneko
67
230k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
Testing 201, or: Great Expectations
jmmastey
46
8.3k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
310
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
440
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
960
Transcript
React✕Socket.ioで人狼サーバを作る 第一章 フロントエンド実装 Ryosuke Uchiyama step63r
コロナ禍になって感じたこと
こんな感じのゲームサーバを作ります
おしながき 4 1. Reactでフロントエンドを実装する 2. Socket.ioでバックエンドを実装する 3. Material UIで見た目を整える 4.
Redisでデータを永続化する 5. クラウドにデプロイする
おしながかない(説明対象外の内容) 5 • HTML, CSS, JavaScript, TypeScriptの基本構文 • JSX記法 •
Class Component • Redux
アプリケーション アーキテクチャ
環境構築
Node.jsをインストール Node.js (nodejs.org)
パッケージをインストール $ npm install –g yarn Yarn $ npm install
–g typescript TypeScript $ yarn global add create-react-app create-react-app
プロジェクト初期化 $ cd ./open-jinro-docker/ プロジェクトのディレクトリに移動 $ mkdir ./client $ mkdir
./server フロントエンド用とバックエンド用のサブディレクトリを作成 フロントエンドの初期化 $ cd ./client/ $ npx create-react-app . --template typescript バックエンドの初期化 $ cd ./server/ $ npm init $ yarn add --dev typescript $ npx tsc --init
Demo Hello React!
Reactとは 状態管理がラク! UIを部品に分けて 作る! 開発途中でも 導入できる!
React採用事例
Reactの基本要素
Component ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); index.tsx function
App() { return ( <div className="App"> <header className="App-header"> // ... </header> </div> ); } App.tsx 画面の各要素を定義するクラスまたはメソッド
Props const props: Props = { message: 'Hello, React!!', };
ReactDOM.render( <React.StrictMode> <App message={props.message} /> </React.StrictMode>, document.getElementById('root') ); index.tsx コンポーネントに渡す引数(設定値) export type Props = { message: string, }; function App(props: Props) { const handleOnClick = () => { console.log(props.message); }; return ( <button onClick={handleOnClick}>ボタン</button> ); } export default App; App.tsx
React Hooks - useState - useEffect
問題提起 function App() { let i = 0; const handleOnClick
= () => { console.log(i++); }; return ( <> <button onClick={handleOnClick}>ボタン</button> <p>現在の i の値は {i} です。</p> </> ); } App.tsx この実装のどこに問題があるのでしょうか…?
再レンダリングが起きる条件 19 1. Stateが更新されたコンポーネント 2. Propsが変更されたコンポーネント 3. 再レンダリングされたコンポーネント配下の全てのコンポーネント
もう一度見てみましょう function App() { let i = 0; const handleOnClick
= () => { console.log(i++); }; return ( <> <button onClick={handleOnClick}>ボタン</button> <p>現在の i の値は {i} です。</p> </> ); } App.tsx 「変数の値が変化した」は再レンダリング条件になりません
useState コンポーネントの状態を表す値 function App() { const [val, setVal] = useState<number>(0);
const handleOnClick = () => { setVal((prev) => prev + 1); console.log(val); }; return ( <> <button onClick={handleOnClick}>ボタン</button> <p>現在の i の値は {val} です。</p> </> ); } App.tsx
ちょっと待てよ
Why? RFClarification: why is `setState` asynchronous? · Issue #11527 ·
facebook/react (github.com) Reactではステートの変更が即時反映されない場合がある - Breath Note (shinki.net) ↓開発元(Facebook)の超長い説明(英文) …は読む気にならないので日本語による解説↓
useEffect コンポーネントの副作用を制御する function App() { const [val, setVal] = useState<number>(0);
useEffect(() => { console.log(val); }, [val]); const handleOnClick = () => { setVal((prev) => prev + 1); }; return ( <> <button onClick={handleOnClick}>ボタン</button> <p>現在の i の値は {val} です。</p> </> ); } App.tsx
React Hooks 機能 使途 useState 状態を管理する useEffect 副作用を管理する useContext グローバルなデータ空間で状態を管理する
useReducer 状態とそれに関連する状態を同時に取り扱う useCallback コールバック関数をメモ化する useMemo 変数の値をメモ化する useRef 要素の参照を取得する useImperativeHandle 参照が使われた時に親コンポーネントに渡されるインスタンス値を改造する useLayoutEffect 同期的に副作用を呼び出す useDebugValue React DevToolsでカスタムフックのラベルを表示する
Reactちょっと応用編 - 配列のレンダリング - 条件付きレンダリング - React Routerでルーティング
配列のレンダリング JSX内でArray.prototype.map()を使う const array: string[] = ['国語', '数学', '英語', '理科',
'社会']; function App() { return ( <> <ul> {array.map((item, index) => ( <li key={index}>{item}</li> ))} </ul> </> ); } App.tsx
条件付きレンダリング 論理積 (&&) の短絡評価を活用する function App() { const [checked, setChecked]
= useState<boolean>(false); const handleCheckboxChanged = (e: React.ChangeEvent<HTMLInputElement>) => { setChecked(e.target.checked); }; return ( <> <input type='checkbox' id='chk' checked={checked} onChange={handleCheckboxChanged} /> <label htmlFor='chk'>チェック</label> {checked && ( <p style={{ fontWeight: 'bold', color: 'red' }}>チェックされてるよ!!</p> )} </> ); } App.tsx
React Routerでルーティング $ yarn add react-router-dom ReactDOM.render( <React.StrictMode> <BrowserRouter> <Routes>
<Route path='/' element={<App />} /> <Route path='/page1' element={<Page1 />} /> <Route path='/page2' element={<Page2 />} /> </Routes> </BrowserRouter> </React.StrictMode>, document.getElementById('root') ); index.tsx function App() { const navigate = useNavigate(); const handleToPage1 = () => { navigate('/page1'); }; const handleToPage2 = () => { navigate('/page2'); }; return ( <> <button onClick={handleToPage1}>Page1へ</button> <button onClick={handleToPage2}>Page2へ</button> </> ); } App.tsx
実践 人狼サーバのフロントエンドを実装する
人狼ゲームの流れ 0日目 夜 無限ループ n = n + 1 n日目
昼 (議論) ゲーム終了判定 ・役職が決定される ・ルール次第では、人狼は襲撃を行う ・ルール次第では、占い師は占いを行う ・人狼の数 = 0 のとき、市民側の勝利 ・市民の数 <= 人狼の数 のとき、人狼側の勝利 ・それ以外のとき、ゲーム続行 ・話し合いにより、追放するプレイヤーを決める
人狼ゲームの流れ ゲーム終了判定 n日目 夜 投票結果判定 n日目 昼 (投票) ・匿名投票により、追放するプレイヤーの多数決を取る ・最多得票者が1人の場合、そのプレイヤーを追放する(対象は以降のゲームに干渉できな
い) ・最多得票者が複数の場合、再度議論のうえ、それらのプレイヤーから決戦投票を行う(決 戦投票の結果、最多得票者がなお複数の場合は誰も追放しない) ・人狼は市民1人を襲撃する(対象は以降のゲームに干渉できない) ・占い師はプレイヤー1人を占う(対象が人狼か否かが分かる) ・狩人(騎士)はプレイヤー1人を守護する(この夜、対象への襲撃は失敗する) ・霊媒師はこの昼に追放したプレイヤーが人狼だったか否かが分かる
トップページ (/) • 「ルームに参加」押下→ ルーム参加ページへ遷移 • 「ルームを作成」押下→ ルーム作成ページへ遷移
ルーム作成ページ (/create) • ユーザー名を入力 • 各役職の人数を入力(合計人数は自動計算) • 「戻る」押下→ トップページへ遷移 •
「作成」押下→ランダムなユーザID (16桁) とルームID (8桁) をサーバ から取得後、ルーム入室リクエストを送信し待機室ページへ遷移 • ユーザー名が入力されていない、またはプレイ人数が最低人数に達し ていない場合は「作成」ボタンを非活性にする
ルーム参加ページ (/join) • ユーザー名を入力 • ルームIDを入力 • 「戻る」押下→ トップページへ遷移 •
「参加」押下→ランダムなユーザID (16桁) をサーバから取得後、ルー ム入室リクエストを送信し待機室ページへ遷移 • ユーザー名とルームIDが入力されていない場合は「参加」ボタンを非 活性にする
待機室ページ (/waiting) • ルームIDを表示(ボタン押下でクリップボードにコピー) • プレイ人数を表示 • 現在待機中のユーザー名を表示 • 「退室する」押下→サーバにルーム退室リクエストを送信しトップ
ページへ遷移 • 「ゲーム開始」押下→サーバに状態更新リクエストを送信しゲーム ページへ遷移 • 参加ユーザー数がプレイ人数と一致しない場合は「ゲーム開始」ボタ ンを非活性にする • 「ゲーム開始」ボタンはホストユーザーのみに表示
ゲームページ(議論) (/game) • 日数と進行フェーズを表示(以降同様) • ユーザーの役職を表示(以降同様) • 役職が人狼かつ人狼が複数人の場合、自分以外の人狼のユーザー名を 表示(以降同様) •
「投票フェーズへ進む」押下→サーバに状態更新リクエストを送信 • 生存中のユーザー名を表示(以降同様) • 追放・襲撃されたユーザー名を表示(以降同様) • 追放・襲撃後は行動選択なし(以降同様) • 追放・襲撃後はユーザー名に役職を付加(以降同様)
ゲームページ(投票) (/game) • 「(各ユーザ名)」押下→サーバに状態更新リクエストを送信 • リクエスト送信後は全員の投票完了を待機した後、サーバから投票結 果を受信
ゲームページ(投票結果) (/game) • 「夜フェーズへ進む」押下→サーバに状態更新リクエストを送信 • リクエスト送信後は全員の確認完了を待機した後、サーバから状態更 新完了を受信
ゲームページ(夜の行動) (/game) • 各役職に応じて必要な選択ボタンを表示 • 人狼:襲撃対象 • 占い師:占う対象 • 霊媒師:この日の昼に追放されたプレイヤーが人狼だったか否か
を表示+「翌日へ進む」ボタン • 狩人(騎士):襲撃から守る対象 • それ以外:「翌日へ進む」ボタンのみ • 各リクエスト送信後は全員の行動完了を待機した後、サーバから状態 更新完了を受信
Appendix
参考文献 44 • any型で諦めない React.EventCallback – Qiita • React hooksを基礎から理解する
(useState編) - Qiita • じゃけぇ『モダンJavaScriptの基本から始める React実践の教科書』(SBクリエイティブ、2021年) • asakohattori『基礎から学ぶReact/React Hooks』(C&R研究所、2021年) • aaa