22-04-20 (3)
React.js
Today I Learned ... react.js
🙋♂️ React.js Lecture
🙋 My Dev Blog
前回のコメント
React.createContext
サブ構成部品用にエクスポートします.
->()に初期値を入力します.
useContext
importのcontext名を作成します.
<Provider value={value}>
->valueパフォーマンスを最適化するにはusemoにキャッシュする必要があります.React Lecture CH 8
1 - context API
2-createContextとProvider
3 - useContext
4-左キー、右キーロジック
5-地雷数表示
6-一度にスペースを開く
7-勝利条件チェック、タイマー
8-context API最適化
マウス左クリック、マウス右クリックロジック
1)左ボタン-OPEN CELL
MineSearch.jsx
const reducer = (state, action) => {
switch (action.type) {
case START_GAME:
return {
...state,
tableData: plantMine(action.row, action.cell, action.mine),
};
// 🔻 추가
case OPEN_CELL: {
const tableData = [...state.tableData];
tableData[action.row] = [...state.tableData[action.row]];
tableData[action.row][action.cell] = CODE.OPENED;
return {
...state,
tableData,
};
}
default:
return state;
}
};
const Td = ({ rowIndex, cellIndex }) => {
const { tableData, dispatch } = useContext(TableContext);
const onClickTd = useCallback(() => {
dispatch({ type: OPEN_CELL, row: rowIndex, cell: cellIndex });
}, []);
return (
<td style={getTdStyle(tableData[rowIndex][cellIndex])} onClick={onClickTd}>
{getTdText(tableData[rowIndex][cellIndex])}
</td>
);
};
onClickTd
関数を作成します.useCallback
使用!->rowおよびcell情報は、それぞれrowIndexおよびcellIndexを表します.
tdをクリックすると白くなります.
すなわちtableData[rowIndex][cellIndex]には
CODE.OPENED
が導入され、gettdStyleは背景を#fff
に設定する.解決すべき問題
onClicktdサブディビジョン
動作は、
tableData[rowIndex][cellIndex]
の値に依存する必要があります.->switch文を使用します.
const onClickTd = useCallback(() => {
switch (tableData[rowIndex][cellIndex]) {
case CODE.OPENED:
case CODE.FLAG_MINE:
case CODE.FLAG:
case CODE.QUESTION_MINE:
case CODE.QUESTION:
return;
case CODE.NORMAL:
dispatch({ type: OPEN_CELL, row: rowIndex, cell: cellIndex });
return;
case CODE.MINE:
dispatch({ type: CLICK_MINE, row: rowIndex, cell: cellIndex });
return;
}
}, [tableData[rowIndex][cellIndex]]);
(状態はOPENED、様式は)
スタイル+テキスト分割
td構成部品のgettdStyleとgettdTextを変更します.
const getTdStyle = (code) => {
switch (code) {
case CODE.NORMAL:
case CODE.MINE:
return {
background: '#444',
};
case CODE.CLICKED_MINE:
case CODE.OPENED:
return {
background: '#fff',
};
case CODE.QUESTION:
case CODE.QUESTION_MINE:
return {
background: 'yellow',
};
case CODE.FLAG:
case CODE.FLAG_MINE:
return {
background: 'red',
};
default:
return {
background: '#fff',
};
}
};
const getTdText = (code) => {
switch (code) {
case CODE.NORMAL:
return '';
case CODE.MINE:
return 'X';
case CODE.CLICKED_MINE:
return '펑';
case CODE.FLAG:
case CODE.FLAG_MINE:
return '!';
case CODE.QUESTION:
case CODE.QUESTION_MINE:
return '?';
default:
return '';
}
};
2)右クリック-onContextMenu
Td.jsx
const onRightClickTd = useCallback(
(e) => {
e.preventDefault();
switch (tableData[rowIndex][cellIndex]) {
case CODE.NORMAL:
case CODE.MINE:
dispatch({ type: FLAG_CELL, row: rowIndex, cell: cellIndex });
return;
case CODE.FLAG:
case CODE.FLAG_MINE:
dispatch({ type: QUESTION_CELL, row: rowIndex, cell: cellIndex });
return;
case CODE.QUESTION:
case CODE.QUESTION_MINE:
dispatch({ type: NORMALIZE_CELL, row: rowIndex, cell: cellIndex });
return;
default:
return;
}
},
[tableData[rowIndex][cellIndex]]
);
// JSX
return (
<td
style={getTdStyle(tableData[rowIndex][cellIndex])}
onClick={onClickTd}
onContextMenu={onRightClickTd}
>
{getTdText(tableData[rowIndex][cellIndex])}
</td>
);
tableData[rowIndex][cellIndex]
の値によって異なる必要があるため、switch文を作成します....
export const START_GAME = 'START_GAME';
export const OPEN_CELL = 'OPEN_CELL';
export const CLICK_MINE = 'CLICK_MINE';
export const FLAG_CELL = 'FLAG_CELL';
export const QUESTION_CELL = 'QUESTION_CELL';
export const NORMALIZE_CELL = 'NORMALIZE_CELL';
その他のstate-stored
const initialState = {
tableData: [],
timer: 0,
result: '',
halted: false, // 👈 추가
};
case CLICK_MINE: {
const tableData = [...state.tableData];
tableData[action.row] = [...state.tableData[action.row]];
tableData[action.row][action.cell] = CODE.CLICKED_MINE;
return {
...state,
tableData,
halted: true,
};
}
halted
はtrueで、ゲームを停止させます.ただし、START GAMEアクションのreturn部分にstrated:falseを追加し、ゲームを再開します.
case START_GAME:
return {
...state,
tableData: plantMine(action.row, action.cell, action.mine),
halted: false,
};
STARTをInitialStateとCREACTContextに追加することもできます.tdコンポーネントからuseContext()を読み込みます.
MineSearch.jsx
export const TableContext = createContext({
tableData: [],
halted: true,
dispatch: () => {},
});
const initialState = {
tableData: [],
timer: 0,
result: '',
halted: true,
};
const { tableData, dispatch, halted } = useContext(TableContext);
->onClicktd、onRightClicktdにあります.
->
halter
trueの場合、セルをクリック(ゲームを停止)const onClickTd = useCallback(() => {
if (halted) {
return;
}
...
}
const onRightClickTd = useCallback(
(e) => {
e.preventDefault();
if (halted) {
return;
}
...
}
残りの減速機の作成
case FLAG_CELL: {
const tableData = [...state.tableData];
tableData[action.row] = [...state.tableData[action.row]];
if (tableData[action.row][action.cell] === CODE.MINE) {
tableData[action.row][action.cell] = CODE.FLAG_MINE;
} else {
tableData[action.row][action.cell] = CODE.FLAG;
}
return {
...state,
tableData,
};
}
case QUESTION_CELL: {
const tableData = [...state.tableData];
tableData[action.row] = [...state.tableData[action.row]];
if (tableData[action.row][action.cell] === CODE.FLAG_MINE) {
tableData[action.row][action.cell] = CODE.QUESTION_MINE;
} else {
tableData[action.row][action.cell] = CODE.QUESTION;
}
return {
...state,
tableData,
};
}
case NORMALIZE_CELL: {
const tableData = [...state.tableData];
tableData[action.row] = [...state.tableData[action.row]];
if (tableData[action.row][action.cell] === CODE.QUESTION_MINE) {
tableData[action.row][action.cell] = CODE.MINE;
} else {
tableData[action.row][action.cell] = CODE.NORMAL;
}
return {
...state,
tableData,
};
}
(二次元配列なので展開しなければなりません)
Result
地雷の数を表示
周囲にどれだけの地雷があるかをスペースで示す
->OPEN CELLのreduceで作成します.
いくつかのスペースしかないところを押すと、一度に周囲のスペースを開くことができます.
->再帰的に実現します.
周辺地雷数
チェックする周囲のセル数が変化します.
->もし
case OPEN_CELL: {
const tableData = [...state.tableData];
tableData[action.row] = [...state.tableData[action.row]];
tableData[action.row][action.cell] = CODE.OPENED;
let around = [];
if (tableData[action.row - 1]) {
around = around.concat(
tableData[action.row - 1][action.cell - 1],
tableData[action.row - 1][action.cell],
tableData[action.row - 1][action.cell + 1]
);
}
around = around.concat(
tableData[action.row][action.cell - 1],
tableData[action.row][action.cell + 1]
);
if (tableData[action.row + 1]) {
around = around.concat(
tableData[action.row + 1][action.cell - 1],
tableData[action.row + 1][action.cell],
tableData[action.row + 1][action.cell - 1]
);
}
const count = around.filter((v) =>
[CODE.MINE, CODE.FLAG_MINE, CODE.QUESTION_MINE].includes(v)
).length;
console.log(around, count);
tableData[action.row][action.cell] = count;
return {
...state,
tableData,
};
}
(元はx.に変更されました.新しい配列を返します)
->filter([].include()を使用して地雷ユニットを格納し、この配列の長さが地雷の個数である.Td.jsx
const getTdText = (code) => {
switch (code) {
...
default:
return code || '';
}
0の場合はスペース(地雷がない場合)を出力します.
次の時間-一度に1つのスペースを開く(再使用可能)
Reference
この問題について(22-04-20 (3)), 我々は、より多くの情報をここで見つけました https://velog.io/@thisisyjin/22-04-20-3テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol