• 카테고리

    질문 & 답변
  • 세부 분야

    프론트엔드

  • 해결 여부

    미해결

Td와 Tr 컴포넌트에 memo를 씌우지 않아도 되나요?

23.05.25 22:30 작성 23.05.25 22:32 수정 조회수 229

0

timer 때문에 Table 전체가 리렌더링되는 문제를 해결하기위해

강의에서는 Table과 하위컴포넌트 Tr, Td 모두에 memo를 씌우셨고
하위컴포넌트가 다 memo가 돼있어야지 상위컴포넌트도 memo를 적용할 수 있게 된다고 말씀하셨는데요


제가 Tr Td에 memo를 없애고
Table에만 적용해봤더니
그래도 리렌더링되지 않길래
이렇게 해도 되는지 궁금해서 질문드립니다

 

import React, { useReducer, createContext, useMemo, useEffect } from 'react';
import Table from './Table';
import Form from './Form';

// 중략
 
const MineSearch = () => {
  const [state, dispatch] = useReducer(reducer, initalState);
  const { tableData, halted, timer, result } = state;

  const value = useMemo(() => ({ tableData: tableData, halted: halted, dispatch })
    , [tableData, halted]);

  useEffect(() => {
    if (!halted) {
      const timer = setInterval(() => {
        dispatch({ type: INCREMENT_TIMER });
      }, 1000);
      return () => {
        clearInterval(timer);
      }
    }
  }, [halted]);
  return (
    <TableContext.Provider value={value}>
      <Form />
      <div>{timer}</div>
      <Table />
      <div>{result}</div>
    </TableContext.Provider>
  );
};

export default MineSearch;
import React, { useContext, memo } from 'react';
import Tr from './Tr';
import { TableContext } from './MineSearch';

const Table = memo(() => {
  const { tableData } = useContext(TableContext);
  return (
    <table>
      {Array(tableData.length).fill().map((tr, i) => <Tr key={i} rowIndex={i} />)}
    </table>
  );
});

export default Table;
import React, { useContext, memo } from 'react';
import Td from './Td';
import { TableContext } from './MineSearch';

const Tr = ({ rowIndex }) => {
  const { tableData } = useContext(TableContext);
  return (
    <tr>
      {tableData[0] && Array(tableData[0].length).fill().map((v, i) => <Td key={i} rowIndex={rowIndex} cellIndex={i} />)}
    </tr>
  );
};

export default Tr;
import React, { useContext, useCallback, memo, useMemo } from 'react';
import {
  TableContext, CODE,
  OPEN_CELL, CLICK_MINE, FLAG_CELL, QUESTION_CELL, NORMALIZE_CELL
} from './MineSearch';

// 중략

const Td = ({ rowIndex, cellIndex }) => {
  const { tableData, dispatch, halted } = useContext(TableContext);

  const onClickTd = useCallback(() => {
    if (halted) {
      return;
    }
    switch (tableData[rowIndex][cellIndex]) {
      case CODE.OPENED:
      case CODE.FLAG:
      case CODE.QUESTION:
      case CODE.FLAG_MINE:
      case CODE.QUESTION_MINE:
        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.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], halted]);


  return (
    <RealTd onClickTd={onClickTd} onRightClickTd={onRightClickTd} data={tableData[rowIndex][cellIndex]} />
  )
};

const RealTd = memo(({ onClickTd, onRightClickTd, data }) => {
  console.log('RealTd rendered');
  return (
    <td
      onClick={onClickTd}
      onContextMenu={onRightClickTd}
      style={getTdStyle(data)}
    > {getTdText(data)}</td>
  );
});

export default Td;

답변 1

답변을 작성해보세요.

0

timer 때문에는 Table만 memo 씌우셔도 됩니다.

다만 셀 데이터때문에는 Tr Td에 씌우셔야할 수 있습니다.

신동마님의 프로필

신동마

2023.11.10

Table에서 props로 Tr, Td에 rowIndex, cellIndex를 순차적으로 적용했기 때문인가요?