지뢰찾기 만들기(6)

29645 단어 ReactReact

Step 6

context API 최적화

react dev tools를 사용하면

리렌더링 될 때 마다 깜빡이는걸 시각적으로 확인 할 수 있다.

timer 때문에 계속 깜빡이므로

Form과 Table 그리고 그 아래에 있는 컴포넌트들을 모두 memo로 묶어준다.



Form.jsx

const Form = memo(() => {
    const [row, setRow] = useState(10); // 줄(세로)
    const [cell, setCell] = useState(10); // 칸(가로)
    const [mine, setMine] = useState(20); // 지뢰 개수
    const { dispatch }= useContext(TableContext);

    // useCallback으로 감싸주면 불필요한 렌더링 막아줌
    const onChangeRow = useCallback((e) => {
        setRow(e.target.value);
    }, []);

    const onChangeCell = useCallback((e) => {
        setCell(e.target.value);
    }, []);

    const onChangeMine = useCallback((e) => {
        setMine(e.target.value);
    }, []);

    const onClickBtn = useCallback(() => {
        dispatch({ type: START_GAME, row, cell, mine});
    }, [row, cell, mine]);

    return (
        <div>
            <input type="number" placeholder="세로" value={row} onChange={onChangeRow} />
            <input type="number" placeholder="가로" value={cell} onChange={onChangeCell} />
            <input type="number" placeholder="지뢰" value={mine} onChange={onChangeMine} />
            <button onClick={onClickBtn}>시작</button>
        </div>
    )
})




Table.jsx

const Table = memo(() => {
    const { tableData } = useContext(TableContext);

    return (
        <table>
            {Array(tableData.length).fill().map((tr, i) => <Tr rowIndex={i} />)}
        </table>
    )

})




Tr.jsx

const Tr = memo(({ rowIndex }) => {
    const { tableData } = useContext(TableContext);

    return (
        <tr>
            {tableData[0] && Array(tableData[0].length).fill().map((td, i) => <Td rowIndex={ rowIndex } cellIndex={i} />)}
        </tr>
    )
})




Td.jsx

const Td = memo(({ rowIndex, cellIndex }) => {
    const { tableData, dispatch, halted } = useContext(TableContext);
    
    const onClickTd = useCallback(() => {
        if (halted) {
            return;
        }
        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;
            default:
                return;
        }
        
    }, [tableData[rowIndex][cellIndex], halted]);

    const onRightClickTd = useCallback((e) => {
        e.preventDefault(); // 디폴트로 메뉴가 뜨는것을 방지
        
        if (halted) {
            return;
        }
        switch (tableData[rowIndex][cellIndex]) {
            case CODE.OPENED:
                return;
            case CODE.NORMAL:
            case CODE.MINE:
                dispatch( {type: FLAG_CELL, row: rowIndex, cell: cellIndex} );
                return;
            case CODE.FLAG_MINE:
            case CODE.FLAG:
                dispatch( {type: QUESTION_CELL, row: rowIndex, cell: cellIndex} );
                return;
            case CODE.QUESTION_MINE:
            case CODE.QUESTION:
                dispatch( {type: NORMAL_CELL, row: rowIndex, cell: cellIndex} );
                return;
            default:
                return;
        }
    }, [tableData[rowIndex][cellIndex], halted]);

    return (
        <td
            style={getTdStyle(tableData[rowIndex][cellIndex])}
            onClick={onClickTd}
            onContextMenu={onRightClickTd}
        >{getTdText(tableData[rowIndex][cellIndex])}
        </td>
    )

})

좋은 웹페이지 즐겨찾기