22-04-20 (3)


React.js


Today I Learned ... react.js🙋‍♂️ React.js Lecture
🙋‍ My Dev Blog

前回のコメント


  • React.createContext
    サブ構成部品用にエクスポートします.
    ->()に初期値を入力します.

  • useContext
    importのcontext名を作成します.
  • JSX内<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;
      }
    };
  • 浅いコピー後([...]);このセルのCODE.OPENEDを指定すればよい.
  • Td.jsx
    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>
      );
    };
  • tdをクリックしてonClickTd関数を作成します.
  • JSXアプリケーションツリーに直接含まれる関数->useCallback使用!
  • dispatchは、useContextとして受信し、その中に動作オブジェクトを入れる.
    ->rowおよびcell情報は、それぞれrowIndexおよびcellIndexを表します.
  • <結果>
    tdをクリックすると白くなります.
    すなわちtableData[rowIndex][cellIndex]にはCODE.OPENEDが導入され、gettdStyleは背景を#fffに設定する.

    解決すべき問題
  • 地雷の部分も白くなります
  • 数字が必要
  • onClicktdサブディビジョン


    動作は、
  • tableData[rowIndex][cellIndex]の値に依存する必要があります.
    ->switch文を使用します.
  • Td.jsx
    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、FLAG、QUESTIONの場合は、クリックしても変更されません.(戻る;終了)
  • NORMAL時にOPEN CELL動作を実行します.
    (状態はOPENED、様式は)
  • MINEをクリックしてCLICK MINEアクションを実行します.(地雷爆発の動作、後ほど作成)
  • useCallback 2番目のパラメータを使用すると、値を変更するたびに関数を再保存できます.
  • スタイル+テキスト分割


    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>
      );
  • 右クリックすると、デフォルトの動作(ポップアップコンテキストメニュー)を防ぐためにe.preventDefaultが実行されます.
  • onRightClicktd関数の動作もtableData[rowIndex][cellIndex]の値によって異なる必要があるため、switch文を作成します.
  • MineSearch.jsx
    ...
    
    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';
    
  • まずexportをモジュールとして使用し、その後すべてtdからインポートする.
  • その他のstate-stored

  • 地雷が爆発したときにゲームを一時停止した状態.
  • const initialState = {
      tableData: [],
      timer: 0,
      result: '',
      halted: false, // 👈 추가
    };
  • CLICK CELL動作を処理するためにreduceを記述する
  • 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,
    };
  • 初期値はtrue、初期ボタンクリック時はfalse.
  • Td.jsx
      const { tableData, dispatch, halted } = useContext(TableContext);
  • 初期値はtrue
  • スタートボタンクリックでfalse
  • if(halted) return; フィルタはになります.
    ->onClicktd、onRightClicktdにあります.
    ->haltertrueの場合、セルをクリック(ゲームを停止)
  • const onClickTd = useCallback(() => {
        if (halted) {
          return;
        }
      ...
    }
      
    const onRightClickTd = useCallback(
        (e) => {
          e.preventDefault();
          if (halted) {
            return;
          }
       ... 
    }
          

    残りの減速機の作成

  • FLAG CELL、QUESTION CELLおよびNORMALIZE CELLのReducer.
  • MineSearch.jsx
    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,
          };
        }
  • すべての原理は同じです.
  • まず、元のデータは変更できないため、tableDataを浅いコピーでコピーします.
  • tableData[action.row]も浅いコピーです.
    (二次元配列なので展開しなければなりません)
  • if-else論理検査を行い、通常ユニット(NORMAL)と地雷ユニット(MINE)を区別する.
  • Result



    地雷の数を表示


  • 周囲にどれだけの地雷があるかをスペースで示す
    ->OPEN CELLのreduceで作成します.

  • いくつかのスペースしかないところを押すと、一度に周囲のスペースを開くことができます.
    ->再帰的に実現します.
  • 周辺地雷数

  • OPEN CELLロジック実装.
  • 上下格が存在するかどうか.
    チェックする周囲のセル数が変化します.
    ->もし
  • MineSearch.jsx
    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,
          };
        }
  • concatは配列と配列を結合します.
    (元はx.に変更されました.新しい配列を返します)
  • 周囲に地雷があるかどうかを計算します.
    ->filter([].include()を使用して地雷ユニットを格納し、この配列の長さが地雷の個数である.Td.jsx
    const getTdText = (code) => {
     switch (code) {
         		...
             default:
         return code || '';
     }
  • デフォルトではcode(=tableData[rowIndex][CellIndex])が出力されます.
    0の場合はスペース(地雷がない場合)を出力します.

  • 次の時間-一度に1つのスペースを開く(再使用可能)