React.js 테이블 동적으로 추가하기

강정우·2023년 2월 26일
0

프로젝트

목록 보기
8/11
post-custom-banner
  • api없이 개발한 코드이다보니 매우 길어질 수 밖에 없었다..
  • 하지만! 어려운 코드는 한개도 없으니 찬찬히 잘 봐주길 바란다.

예제코드

jsx 코드

return (
  <Rnd minWidth={100} minHeight={100} bounds={"parent"}
    default={{x: props.positionX, y: props.positionY, width: props.width, height: props.height + 23}}
    disableDragging={dragable} onDragStart={dragStart} onDragStop={dragStop} onResize={resizeStart}
    onResizeStop={resizeStop}
    style={{zIndex: props.positionZ}}
    >
    <div className={classes.postIt} style={{width: diagramWidth, height: diagramHeight + 23}}
      onMouseEnter={mouseIn} onMouseLeave={mouseOut}>
      <span className={classes.tab} ref={tabRef}>
        {isEdit ? editComponent : defaultComponent}
      </span>
      <table className={classes.table} style={{
          width: isFirstLoad ? props.width : +picWidth,
            height: isFirstLoad ? props.height : +picHeight - 23,
        }}>
        <thead>
          <tr>
            {isEdit ? titleEditComponent : titleComponent}
          </tr>
        </thead>
        <tbody>
          {isEdit ? contentEditComponent : contentComponent}
        </tbody>
      </table>
    </div>
  </Rnd>
)
  • 최상단 Rnd는 다른곳에서 포스팅 했으니 넘어가고
  • 중간중간 들어있는 표현식만 봐주면 된다.

표현식 코드-1 (최상단부 수정 or 일반)

const editComponent = (<>
    <span className={classes.tabText}>
      <FontAwesomeIcon className={classes.icon} style={{color: "orange"}} icon={faArrowsLeftRightToLine}/>
      <button onClick={() => {addColumn(props.id)}}>+</button>
      {props.table.titles.length}
      <button onClick={() => {deleteColumn(props.id)}}>-</button>
    </span>
    
    <span className={classes.tabText}>
      <FontAwesomeIcon className={classes.icon} style={{color: "orange"}}icon={faArrowDownWideShort}/>
      <button onClick={() => {addRow(props.id)}}>+</button>
      {props.table.contents.length}
      <button onClick={() => {deleteRow(props.id)}}>-</button>
    </span>
    
    <span className={classes.tabBtn} onClick={editEvent}>
      <FontAwesomeIcon className={classes.icon}style={{color: "green"}} icon={faCheck}/>
    </span>
    </>)


const defaultComponent = (<>
    <span onClick={closeEvent}>
      <FontAwesomeIcon className={classes.icon} style={{color: "red"}}icon={faCircleXmark}/>
    </span>
    <span onClick={editEvent}>
      <FontAwesomeIcon className={classes.icon} style={{color: "yellow"}} icon={faGears}/>
    </span>
    <span onClick={pinEvent}>
      <FontAwesomeIcon className={classes.icon} style={{color: dragable ? "green" : "yellow"}} icon={faThumbtack}/>
    </span>
    </>)
  • 중간에 들어있는 fontAwesome 코드는 앞서 포스팅 했으니 넘어가겠다.
  • props로 부터 넘겨받는 값은 RTK에서 넘겨받는 값과 같다.
  • 중간중간 보이는 "파랑색 메서드"들을 밑에서 자세히 보겠다.

표현식 코드-2 (title edit input)

const titleComponent = (<>
    {props.table.titles.map((title, index) => (
      <td key={"T" + index}>{title}</td>
    ))}
    </>)

const titleEditComponent = (<>
    {props.table.titles.map((title, index) => (
      <td key={"T" + index}><input className={classes.editInput} type={"text"} defaultValue={title}
                              onChange={e => {
            updateTable({id: props.id, i: index, type: "title", value: e.target.value})
          }}/></td>
    ))}
    </>)
  • thead의 edit 모드는 tbody보다 훨씬 코드가 간결하다.
    한줄만 edit으로 바꿔주면 되기 때문

  • 이때 input 값으로 모두 바꿔주고 onChange에 "파랑색 메서드"를 추가해주면 된다.

표현식 코드-3 (body edit input)

const contentComponent = (<>
        {props.table.contents.map((content, index) => (
            <tr key={"B" + index}>
                {content.map((data, index) => (
                    <td key={index}>{data}</td>
                ))}
            </tr>
        ))}
    </>)
    const contentEditComponent = (<>
        {props.table.contents.map((content, colIndex) => {
            return (
                <tr key={"B" + colIndex}>
                    {content.map((data, index) => (
                        <td key={index}><input className={classes.editInput} 
                                               type={"text"} 
                                               defaultValue={data}
                                               onChange={e => {
                                                   updateTable({
                                                       id: props.id, column: colIndex, type: "content",
                                                       i: index, value: e.target.value
                                                   })
                                               }}/>
                         </td>
                    ))}
                </tr>
            )
        })}
    </>)
  • body는 첫줄 돌고 그 길이만 큼 열을 만들어야하기 때문에 2중 반복문을 써줘야한다.

"파란색 매서드" (table-slice)

  • Redux-ToolKit으로 만든 슬라이스로 메서드를 생성하여 관리하였다.

행 추가 제거 메서드

addColumn(state, action) {
  const editAry = state.tableData.find((table) => table.id === action.payload);
  editAry.contents.titles.push("타이틀")
  for(let i =0; i<editAry.contents.contents.length;i++){
    editAry.contents.contents[i].push("내용")
  }
},
deleteColumn(state, action) {
  const editAry = state.tableData.find((table) => table.id === action.payload);
  editAry.contents.titles.pop()
  for(let i =0; i<editAry.contents.contents.length;i++){
    editAry.contents.contents[i].pop()
  }
}
  • +, - 버튼을 누르면 행을 추가, 제거해주는 매서드이다.
  • payload에 담긴 id값을 토대로 해당 list를 찾아서 데이터를 추가, 제거(pop) 해주는 메서드이다.

열 추가 제거 메서드

addRow(state, action) {
  const editAry = state.tableData.find((table) => table.id === action.payload);
  editAry.contents.contents.push(Array(editAry.contents.titles.length).fill("내용"))
},
deleteRow(state, action) {
  const editAry = state.tableData.find((table) => table.id === action.payload);
  editAry.contents.contents.pop()
}
  • +, - 버튼을 누르면 열을 추가, 제거해주는 매서드이다.
  • 보면 열 데이터를 추가하는 메서드에 titles.length가 왜 있을까 하면
    "행"의 개수만큼 열을 만들어줘야하기 때문이다.

업데이트 메서드

updateTable(state, action) {
  const newData = action.payload;
  const editAry = state.tableData.find((table) => table.id === newData.id);
  if (action.payload.type === 'title') {
    editAry.contents.titles[newData.i] = newData.value
  } else {
    editAry.contents.contents[newData.column][newData.i] = newData.value
  }
},
  • onChange에 걸어둔 method로 따로 title과 content를 만들어도 되지만 하나의 메서드만 두고자 onChange로 값이 변화할 때 매개변수로 type을 지정받아서 위의 코드를 실행하도록 만들었다.

  • input값이 String이 아닌 number이기에 onChange를 걸어도 부하는 없을 듯 하다.

profile
智(지)! 德(덕)! 體(체)!
post-custom-banner

0개의 댓글