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
AI感のないAWS構成図をAIエージェントに描かせたい!
sagochiko
2
480
10年欲しかった音楽管理アプリを、AIと一緒に作りはじめた
judau
1
190
AI臭い文章とは何なのか
nasuvitz
36
75k
20260929_AmazonGuardDutyの検出通知メールにAWS DevOpsAgentの調査結果を追加する
yhana
1
380
2026-09-26 Platform Engineering Kaigi 2026 インフラとアプリの境界線と委譲の設計 / Drawing the Infra and App Line
masasuzu
0
510
雪かき部 #7 もう怖くない!SELECT文!
foursue
0
240
The seven pitfalls of AI (revised version)
ufried
0
140
Oracle Cloud Infrastructure(OCI):Onboarding Session(はじめてのOCI/Oracle Supportご利⽤ガイド)
oracle4engineer
PRO
3
21k
認知負荷を吸収し、プロダクトをまたぐPR Preview基盤の設計事例
taiki45
2
550
顧客の成果創出とプロダクトの成長を 両立するためのFDE
sansantech
PRO
0
520
DORA_Metrics.pdf
wagnerfusca
1
140
全社共通データ基盤をつくる。ソニーのDatabricks活用とデータガバナンス設計の裏側
sony
0
260
Featured
See All Featured
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
560
How to Talk to Developers About Accessibility
jct
2
560
Balancing Empowerment & Direction
lara
6
1.3k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
390
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.7k
Designing for Timeless Needs
cassininazir
1
510
Designing Dashboards & Data Visualisations in Web Apps
destraynor
232
55k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.2k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
550
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
270
We Have a Design System, Now What?
morganepeng
55
8.3k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
380
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