Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
React x Socket.ioで人狼サーバを作る 第一章 フロントエンド実装
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Ryosuke Uchiyama
February 11, 2022
Technology
22
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
54
PythonでSlack通知botを作る
step63r
0
21
ChatGPT実践
step63r
1
370
IoT実践! 行先予定表を電子ペーパーで作る
step63r
0
27
深層強化学習で東方AI 第一章 DQNの基本
step63r
0
300
Build 2021 プレイバック
step63r
0
38
WPFで実践アプリ開発! 第四章 機能の実装 Part 2
step63r
0
53
WPFで実践アプリ開発! 第三章 機能の実装 Part 1
step63r
0
130
WPFで実践アプリ開発! 第二章 UI
step63r
0
170
Other Decks in Technology
See All in Technology
起点・思考・出力で分解する 〜PM業務の自動化設計〜
kazu_kichi_67
2
1.1k
そこにあるから地図ができる~位置を示す"モノ"を愉しむ~ - Interface 2026年6月号GPS特集オフ会 / interface_202606_GPS_offline
sakaik
1
110
螺旋型キャリアの生存戦略 / kinoko-conf2026
rakus_dev
1
1.2k
テスト設計の本質を改めて考えてみる~生成AIを活用する時代だからこそ、作ったテストの説明性を高めよう~
yamasaki696
1
120
When Platform Engineering Meets GenAI
sucitw
0
200
「ビジネスがわかるエンジニア」とは何か?
ryooob
0
350
[AWS Summit Japan 2026]迷っているあなたへ_小さな一歩が、やがて自分を助けてくれる
sh_fk2
2
430
Hatena Engineer Seminar 37 jj1uzh
jj1uzh
0
140
BPaaSで進むAIオペレーションの現在地 AI実装が効く領域とスケーラビリティの選定と実装
kentarofujii
0
210
初めてのDatabricks勉強会
taka_aki
2
180
脱SaaS!FDEを支えるプロビジョニングと分離設計
knih
0
300
ご挨拶「10周年を迎える共創ラボのこれまでとこれから」
iotcomjpadmin
0
150
Featured
See All Featured
Thoughts on Productivity
jonyablonski
76
5.2k
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
1
360
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
260
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
The Cult of Friendly URLs
andyhume
79
6.9k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
200
Ruling the World: When Life Gets Gamed
codingconduct
0
260
The Spectacular Lies of Maps
axbom
PRO
1
820
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
300
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
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