Skip to content

Commit f8e865b

Browse files
authored
Merge pull request #8 from nekketsu2010/react-sokushu-part9
速習 React 第2版 Part9が完了した
2 parents 9cd9cff + 8651ebe commit f8e865b

12 files changed

+261
-22
lines changed

src/App.css

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,45 @@
1-
.current {
2-
background-color: yellow;
1+
.App {
2+
text-align: center;
3+
}
4+
5+
.App-logo {
6+
height: 40vmin;
7+
pointer-events: none;
8+
}
9+
10+
@media (prefers-reduced-motion: no-preference) {
11+
.App-logo {
12+
animation: App-logo-spin infinite 20s linear;
13+
}
14+
}
15+
16+
.App-header {
17+
background-color: #282c34;
18+
min-height: 100vh;
19+
display: flex;
20+
flex-direction: column;
21+
align-items: center;
22+
justify-content: center;
23+
font-size: calc(10px + 2vmin);
24+
color: white;
25+
}
26+
27+
.App-link {
28+
color: #61dafb;
29+
}
30+
31+
@keyframes App-logo-spin {
32+
from {
33+
transform: rotate(0deg);
34+
}
35+
to {
36+
transform: rotate(360deg);
37+
}
38+
}
39+
40+
.border {
41+
border: 1px solid #000000;
42+
margin: 10px;
43+
padding: 10px;
44+
width: 50%;
345
}

src/App.js

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,10 @@
1-
import { NavLink, Outlet } from 'react-router-dom';
21
import './App.css';
3-
4-
// b. スタイルを決定するための関数
5-
function isCurrent({ isActive }) {
6-
return isActive ? 'current' : undefined;
7-
}
2+
import MyCustom from './MyCustom';
83

94
export default function App() {
105
return (
116
<>
12-
<ul>
13-
{/* a. 現在のページを表すリンクに対してスタイルを適用 */}
14-
<li><NavLink end className={ isCurrent } to="/">トップ</NavLink></li>
15-
<li><NavLink className={ isCurrent } to="/hello">Hello</NavLink></li>
16-
<li><NavLink className={ isCurrent } to="/article/13">公開記事 No.13</NavLink></li>
17-
<li><NavLink className={ isCurrent } to="/article/108">公開記事 No.108</NavLink></li>
18-
<li><NavLink className={ isCurrent } to="/article/?id=108">公開記事(クエリ対応)</NavLink></li>
19-
<li><NavLink className={ isCurrent } to="/search/hello/whats/your/name">検索</NavLink></li>
20-
<li><NavLink className={ isCurrent } to="/book/978-4-297-13062-6">書籍情報</NavLink></li>
21-
<li><NavLink className={ isCurrent } to="/post">書籍登録</NavLink></li>
22-
</ul>
23-
<hr />
24-
<Outlet />
7+
<MyCustom />
258
</>
269
);
2710
}

src/MyAppContext.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { createContext, useState } from "react";
2+
3+
export const MyAppContext = createContext();
4+
5+
export function MyAppProvider(props) {
6+
const [count, setCount] = useState(0);
7+
const [count2, setCount2] = useState(0);
8+
const value = { count, setCount, count2, setCount2 };
9+
// 配下のコンテンツにコンテキストを提供
10+
return (
11+
<MyAppContext.Provider value={value}>
12+
{props.children}
13+
</MyAppContext.Provider>
14+
);
15+
}

src/MyCount1.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { MyAppProvider } from './MyAppContext';
2+
import './App.css';
3+
import MyCount2 from './MyCount2';
4+
5+
export default function MyCount1() {
6+
return (
7+
// b. コンテキストに値を引き渡す
8+
<MyAppProvider>
9+
<div className="border">
10+
MyCount1
11+
<MyCount2 />
12+
</div>
13+
</MyAppProvider>
14+
)
15+
}
16+

src/MyCount2.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import MyCount3 from './MyCount3';
2+
import MyCount4 from './MyCount4';
3+
4+
5+
export default function MyCount2() {
6+
return (
7+
<div className='border'>
8+
MyCount2
9+
<MyCount3 />
10+
<MyCount4 />
11+
</div>
12+
)
13+
}

src/MyCount3.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { useContext, useMemo } from "react";
2+
import { MyAppContext } from "./MyAppContext";
3+
4+
export default function MyCount3() {
5+
// a. コンテキスト値を取得
6+
const { count, setCount } = useContext(MyAppContext);
7+
return useMemo(() => {
8+
// ログを出力
9+
console.log('MyCount3 is updated.');
10+
return (
11+
<div className="border">
12+
MyCount3
13+
<div>
14+
{/* b. コンテキスト値を更新&参照 */}
15+
<input type="button" value=" カウント " onClick={ () => setCount(count + 1) } />
16+
<p>{count}回、クリックされました。</p>
17+
</div>
18+
</div>
19+
);
20+
}, [count, setCount])
21+
}

src/MyCount4.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { useContext } from "react";
2+
import { MyAppContext } from "./MyAppContext";
3+
4+
export default function MyCount4() {
5+
const { count2, setCount2 } = useContext(MyAppContext);
6+
// ログを出力
7+
console.log('MyCount4 is updated.');
8+
// count2を更新
9+
return (
10+
<div className="border">
11+
MyCount4
12+
<div>
13+
<input type="button" value=" カウント2 " onClick={ () => setCount2(count2 + 1) } />
14+
<p>{count2}回、クリックされました。</p>
15+
</div>
16+
</div>
17+
)
18+
}

src/MyCustom.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import useCustom from "./useCustom";
2+
3+
export default function MyCustom() {
4+
// a. カスタムフックuseCustomから再利用可能な情報を取得
5+
const [state, increment, decrement, reset] = useCustom(0);
6+
// b. コンポーネントの最終的な出力
7+
return (
8+
<>
9+
<input type="button" value=" カウントアップ " onClick={increment} />
10+
<input type="button" value=" カウントダウン " onClick={decrement} />
11+
<input type="button" value=" リセット " onClick={reset} />
12+
<p>{state.count}回、クリックされました。</p>
13+
</>
14+
)
15+
}

src/MyReducer.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { useReducer } from "react";
2+
3+
export default function MyReducer() {
4+
// a. StateとReducerを準備
5+
const [state, dispatch] = useReducer(
6+
// Stateを更新するための関数(Reducer)
7+
(state, action) => {
8+
switch (action.type) {
9+
// b. PLUS操作ではカウンター値をインクリメント
10+
case 'PLUS':
11+
return { count: state.count + 1 };
12+
// c. それ以外の操作では現在のState値をそのまま返す
13+
default:
14+
return state;
15+
}
16+
},
17+
// Stateの初期値
18+
{
19+
count: 0
20+
}
21+
);
22+
// d. Reducer経由でStateを更新
23+
function increment() {
24+
dispatch({ type: 'PLUS' });
25+
}
26+
// コンポーネントによる描画内容
27+
return (
28+
<>
29+
<input type="button" value=" カウント " onClick={increment} />
30+
<p>{state.count}回、クリックされました。</p>
31+
</>
32+
)
33+
}

src/MyReducerEx.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { useReducer } from "react";
2+
3+
export default function MyReducerEx() {
4+
const [state, dispatch] = useReducer((state, action) => {
5+
// a. アクションの種類に応じて処理を分岐
6+
switch (action.type) {
7+
case 'PLUS':
8+
return { count: state.count + action.step };
9+
case 'MINUS':
10+
return { count: state.count - action.step };
11+
case 'RESET':
12+
return { count: 0 };
13+
default:
14+
return state;
15+
}
16+
}, {
17+
count: 0
18+
});
19+
// ボタンクリック時に呼び出されるイベントハンドラー
20+
function increment() {
21+
dispatch({ type: 'PLUS', step: 5 });
22+
}
23+
function decrement() {
24+
dispatch({ type: 'MINUS', step: 5 });
25+
}
26+
function reset() {
27+
dispatch({ type: 'RESET' });
28+
}
29+
30+
// コンポーネントによる描画内容
31+
return (
32+
<>
33+
<input type="button" value=" カウントアップ " onClick={increment} />
34+
<input type="button" value=" カウントダウン " onClick={decrement} />
35+
<input type="button" value=" リセット " onClick={reset} />
36+
<p>{state.count}回、クリックされました。</p>
37+
</>
38+
)
39+
}

src/MyState.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1-
import { useState } from "react";
1+
import { useState, useEffect } from "react";
22

33
export default function MyState(props) {
44
// a. Stateの初期値を設定
55
const [count, setCount] = useState(0);
6+
7+
// コンポーネントの(再)描画時に実行
8+
useEffect(() => {
9+
const t = setInterval(() => {
10+
setCount(c => c + 1);
11+
}, 1000);
12+
13+
return () => {
14+
clearInterval(t);
15+
};
16+
}, []);
17+
618
// c. count値をインクリメント(イベントハンドラー)
719
function increment() {
820
setCount(count + 1);

src/useCustom.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { useReducer } from "react";
2+
3+
// a. カスタムフックを定義
4+
export default function useCustom(init) {
5+
// b. Reducer(dispatch)、Stateを準備
6+
const [state, dispatch] = useReducer((state, action) => {
7+
switch (action.type) {
8+
case 'PLUS':
9+
return { count: state.count + action.step };
10+
case 'MINUS':
11+
return { count: state.count - action.step };
12+
case 'RESET':
13+
return { count: init };
14+
default:
15+
return state;
16+
}
17+
}, {
18+
count: init
19+
});
20+
// Action呼び出しのための関数
21+
function increment() {
22+
dispatch({ type: 'PLUS', step: 5 });
23+
}
24+
function decrement() {
25+
dispatch({ type: 'MINUS', step: 5 });
26+
}
27+
function reset() {
28+
dispatch({ type: 'RESET' });
29+
}
30+
// c. 呼び出し元で利用したい情報
31+
return [state, increment, decrement, reset];
32+
}

0 commit comments

Comments
 (0)