토글 기능 구현하기

YJS·2023년 9월 19일
0

😖문제 상황

리액트에서 리스트 화면을 출력할때 상위 행을 클릭하면 그에 해당하는 하위 행들을 노출하고 다시 한번 더 클릭하면 비노출 시키는 기능을 구현하고 싶었는데 난관에 부딪혔다. (부모 카테고리에 해당하는 자식 카테고리들을 노출)

문제 코드 )

export default function productCategoryList() {
  const methods = useForm({
    mode: "onChange",
  });

  const {
    register,
    control,
    watch,
    handleSubmit,
    formState: { errors },
  } = methods;

  const { data } = useCategoryListQuery();
  

  return (
        <TableContainer>
          <Table>
            <TableHead>
              <TableRow>
                <StyledTableCellHead>카테고리</StyledTableCellHead>
              </TableRow>
            </TableHead>
            {data && (
              <TableBody>
                {data.map((item) => (
                  <React.Fragment key={item.id}>
                    <TableRow>
                      <StyledTableCellHead>{item.name}</StyledTableCellHead>
                    </TableRow>
                  </React.Fragment>
                ))}
              </TableBody>
            )}
          </Table>
        </TableContainer>
  );
}

🤓문제 해결 과정

step1. 부모 카테고리 클릭 시 toggleRow 이벤트를 추가하여 매개변수로 어떤 행이 클릭 된건지 전달하기

	<TableRow
		onClick={() => toggleRow(item.id)}
    	style={{ cursor: "pointer" }}
	>

step2. toogleRow함수가 호출되면 expandedRows 배열에 아이디를 추가하기.

  const [expandedRows, setExpendedRows] = useState<number[]>([]);
	const toggleRow = (rowId: number) => {
    if (expandedRows.includes(rowId)) {
      setExpendedRows(expandedRows.filter((id) => id !== rowId));
    } else {
      setExpendedRows([...expandedRows, rowId]);
    }
  };

클릭된 부모 행들의 상태를 관리하기 위해 expandedRows 배열을 만든다.(expandedRows는 하위 카테고리를 보여줄 상위 카테고리의 아이디만 담은 배열)
처음 페이지를 로드할때는 클릭된 아이템이 없으므로 expandedRows배열은 비어있게 된다.
그 이후 예를 들어 1번 아이템을 클릭했다면 expandedRows.includes조건이 false이므로 expandedRows에 rowId를 추가한다.
다시 한번 1번 아이템을 클릭한다면 이번에는 expandedRows.includes조건이 true이므로 expandedRows에 클릭된 rowId와 기존에 존재하는 id를 비교해서 같지 않은 경우 = 즉, 다시 한번 클릭되지 않은 경우만 filter 함수를 사용해서 남긴다.

step3. 화면에서 expandedRows에 해당하는 경우에만 하위 카테고리 행 노출하기

	 {expandedRows.includes(item.id) &&
                      item.subCategory.map((i, index) => (
                        <TableRow key={index}>
                          <StyledTableCell>{i.name}</StyledTableCell>
                        </TableRow>
                      ))}

expandedRows가 item.id(부모 카테고리 아이디)를 가지고 있다면 item.subCategory를 화면에 그리도록 처리했다.

🤗해결 방법

해결된 코드)

export default function productCategoryList() {
  const methods = useForm({
    mode: "onChange",
  });

  const {
    register,
    control,
    watch,
    handleSubmit,
    formState: { errors },
  } = methods;

  const { data } = useCategoryListQuery();
  const [expandedRows, setExpendedRows] = useState<number[]>([]);

  const toggleRow = (rowId: number) => {
    if (expandedRows.includes(rowId)) {
      setExpendedRows(expandedRows.filter((id) => id !== rowId));
    } else {
      setExpendedRows([...expandedRows, rowId]);
    }
  };

  return (
        <TableContainer>
          <Table>
            <TableHead>
              <TableRow>
                <StyledTableCellHead>카테고리</StyledTableCellHead>
              </TableRow>
            </TableHead>
            {data && (
              <TableBody>
                {data.map((item) => (
                  <React.Fragment key={item.id}>
                    <TableRow
                      onClick={() => toggleRow(item.id)}
                      style={{ cursor: "pointer" }}
                    >
                      <StyledTableCellHead>{item.name}</StyledTableCellHead>
                    </TableRow>
                    {expandedRows.includes(item.id) &&
                      item.subCategory.map((i, index) => (
                        <TableRow key={index}>
                          <StyledTableCell>{i.name}</StyledTableCell>
                        </TableRow>
                      ))}
                  </React.Fragment>
                ))}
              </TableBody>
            )}
          </Table>
        </TableContainer>
  );
}
profile
우당탕탕 개발 일기

0개의 댓글