[ react ] 게시물 Edit (수정)하기

Suji Kang·2023년 10월 22일
0
post-thumbnail
post-custom-banner

🐾 careerViewTable에 있는거 props넘겨서 사용하기

careerViewTable.js

return (
   <tbody>
      {careerList.map((e) =>
        <CareerRow 
          key={e.id}
          career={e} 
          checkedRowId {checkedRowId}  
          onDeleteCareer={onDeleteCareer} 
          onSelect={onSelect}
      />)}
   </tbody>
);

📌 Edit mode설정하기

careerRow.js

import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
import EditIcon from "@mui/icons-material/Edit";
import { useState } from "react";

const CareerRow = (props) => {
   // 만일 isEdit에 true가 들어있으면 해당 행이 수정 상태임 을 의미하고
    // isEdit에 false가 들어있으면 해당 행이 수정상태가 아님 을 의미한다
   const [isEdit, setIsEdit] = useState(false);
  
   const dateFormat = (date) => {
        // '2023년10월01일' --> '2023-10-01'
        return date
            .replace("년", "-")
            .replace("월", "-")
            .replace("일", "")
            .replace(/ /g, "");  // / /g --> 모든 띄어쓰기 공백 을 의미
    };
  
    // props.career = e;
    // props.checkedRowId
    const e = props.career;
    const { checkedRowId, onSelect, onDeleteRow } = props;

    return (
        <tr>
            <td>
                <input
                    type="checkbox"
                    checked={checkedRowId.includes(e.id)}
                    onChange={() => {
                        onSelect(e.id);
                    }}
                />
            </td>
            <td> {isEdit ? <input defaultValue={e.company} /> : e.company} </td>
            <td> {isEdit ? <input defaultValue={e.position} /> : e.position} </td> //isEdit이 true면 input, false이면 e.position 원래값.
            <td style={{ display: "flex" }}>
                {isEdit ? (
                    <input defaultValue={dateFormat(e.start_date)} type="date" />
                ) : (
                    e.start_date
                )}
                -
                {isEdit ? (
                    <input type="date" defaultValue={dateFormat(e.end_date)} />
                ) : (
                    e.end_date
                )}
            </td>
            <td
                onClick={()=> onDeleteRow(e.id);
                style={{
                    cursor: "pointer",
                }}
            >
                {isEdit ? <EditIcon /> : <DeleteOutlineIcon />}
            </td>
        </tr>
    );
};

export default CareerRow;

📌 선택한 아이들이 클릭된다(edit mode).

careerRow.js

// 상태를 수정상태로 변경해주는 함수
    const onEditState = () => {
        setIsEdit(true);
    };
      
      return(
         <td onClick={onEditState}>
                {isEdit ? <input ref={companyInputRef} defaultValue={e.company} /> : e.company}
            </td>
            <td onClick={onEditState}>
                {isEdit ? <input ref={positionInputRef} defaultValue={e.position} /> : e.position}
              //isEdit이 true면 input, false이면 e.position 원래값.
            </td>
            <td onClick={onEditState} style={{ display: "flex" }}>
                {isEdit ? (
                    <input ref={startDateInputRef} defaultValue={dateFormat(e.start_date)} type="date" />
                ) : (
                    e.start_date
                )}
                -
                {isEdit ? (
                    <input ref={endDateInputRef} type="date" defaultValue={dateFormat(e.end_date)} />
                ) : (
                    e.end_date
                )}
            </td>
        );

📌 이제는 실제로 수정하는대로 데이터베이스에도 수정이 되어야한다.

state변수를 사용해도 되지만, 사용하면 렌더링이 되는데 굳이 렌더링이되어 화면이 다시 그려지게할 필요는 없다.
그래서, 여기서 useRef() 객체를 를 사용한다. (자기 자신은 변경해도 re-rendering은 하지 않는다. )

careerRow.js

 const onEditClick = async (id) => {
        // id에는 수정할 행의 id가 들어있음
        // 수정하기 버튼 클릭시 실행될 함수
        // 1. 사용자가 입력한 company, postion, startDate, endDate 가져오기
        const company = companyInputRef.current.value;
        const position = positionInputRef.current.value;
        const startDate = startDateInputRef.current.value;
        const endDate = endDateInputRef.current.value;
   
  return(
     		<td onClick={onEditState}>
                {isEdit ? <input ref={companyInputRef} defaultValue={e.company} /> : e.company}
     		</td>
            <td onClick={onEditState}>
                {isEdit ? <input ref={positionInputRef} defaultValue={e.position} /> : e.position}
            </td>
            <td onClick={onEditState} style={{ display: "flex" }}>
                {isEdit ? (
                    <input ref={startDateInputRef} defaultValue={dateFormat(e.start_date)} type="date" />
                ) : (
                    e.start_date
                )}
                -
                {isEdit ? (
                    <input ref={endDateInputRef} type="date" defaultValue={dateFormat(e.end_date)} />
                ) : (
                    e.end_date
                )}
            </td>
    );

📌 간단히 유효성 검사를한다.

careerRow.js

import { useRef } from "react";

 const onEditClick = async (id) => {
    // id에는 수정할 행의 id가 들어있음
    // 수정하기 버튼 클릭시 실행될 함수
    // 1. 사용자가 입력한 company, postion, startDate, endDate 가져오기
        const company = companyInputRef.current.value;
        const position = positionInputRef.current.value;
        const startDate = startDateInputRef.current.value;
        const endDate = endDateInputRef.current.value;
   
 // 유효성 검사
        if (company === '') {
            alert('회사명은 필수입력입니다');
            return;
        }
        if (position === '') {
            alert('직책은 필수입력 입니다');
            return;
        }
        if (startDate === '') {
            alert('시작일은 필수입력 입니다');
            return;
        }
        const today = new Date();
        const startDateTmp = new Date(startDate);

        if (startDateTmp > today) {
            alert('시작일은 오늘 날짜를 넘어가면 안됩니다');
            return;
        }

        if (endDate !== '') {
            const endDateTmp = new Date(endDate);
            if (endDateTmp < startDateTmp) {
                alert('종료일은 시작일보다 이전으로 설정할 수 없습니다')
                return;
            }

            if (endDateTmp > today) {
                alert('종료일은 오늘 날짜를 넘어가면 안됩니다');
                return;
            }
        }

return (
   <td onClick={() => {
       if (isEdit) { 
         onEditClick(e.id);
       } else {              
         onDeleteRow(e.id);
       }
    }}
	style={{
      cursor: "pointer",
      }}
    >
     {isEdit ? <EditIcon /> : <DeleteOutlineIcon />}
   </td>
  );

📌 서버에 입력한 값들을 전달하여 Edit요청하기

careerRow.js

import axios from "axios";
import { useContext, useRef, useState } from "react";
import { UserContext } from "../../App";

 const { accessToken } = useContext(UserContext); //전역변수에 저장한거를 가져온다 accessToken안에 토큰이 들어있다. 

 // props.career = e;
 // props.checkedRowId
    const e = props.career;
    const { checkedRowId, onSelect, onDeleteRow } = props;

 // 유효한 값들이 입력되었음을 확인한다면
 // express 서버에 입력한 값들을 전달하여 수정 요청하기
        try {
            await axios.put('/api/careers', { company, position, startDate, endDate, id }, // body에 넣어서
                { headers: { Authorization: `Bearer ${accessToken}` } } //로그인했을때만 사용할수있으니까, headers에 토큰 전달.
            )
            alert('수정완료~!');
            setIsEdit(false); // 수정이 완료된후, -> 수정상태를 false 로바꾸기
            // e 안에 있는 company, position , startDate, endDate 변경
            e.company = company;
            e.position = position;
            e.start_date = startDate;
            e.end_date = endDate;
        } catch (err) {
            console.log(err);
            alert('오류발생');
        }
 };

📌 react에서 넘겨준 값들 가져오기

app.js

app.put('/api/careers', async (req, res) => {
    //react에서 넘겨준 값들(수정값들)
    console.log(req.body); //body안에는 {company: 'starbuck' , position: 'barista', startDate: '2022-01-01', endDate: '2023-01-01' } 가 들어있다. 
    const { company, position, startDate, endDate, id } = req.body;  //req.body 안에서 꺼내올, company, position, startDate, endDate, id를 적는다. 

    // 로그인 유저가 요청했는지 여부 검사
    console.log(req.headers.authorization);
    let token = req.headers.authorization.replace('Bearer ', ''); //토큰을 가져오고. -> 여기서, req.headers.authorization
    try {
        jwt.verify(token, process.env.JWT_SECRET)
    } catch (err) {
        res.status(403).json('토큰이 만료되었으니 다시 로그인 필요');
        return;
    }

    // 정상적인 토큰이라면 mysql 가서 수정 요청
    let sql = `
      UPDATE tbl_careers
      SET company = ?, position= ?, start_date = ?, end_date= ?
      WHERE id = ?
    `;
    try {
        await pool.query(sql, [company, position, startDate, endDate, id]);
        res.send('수정 완료!');
    } catch (err) {
        console.log(err);
        res.status(500).json('오류 발생함!');
    }
});

그러면 이제 데이타베이스에도 수정이 잘 되었다~!👍


🐾 경력이 눌리면 색깔이 경력으로 가고, 활동게시판을 누르면, 활동게시판으로 가게 만들기.

📝 result

sidebar.js

const DashboardSidebar = (props) => {
  // props.isOpen 

  let items = [
    { icon: <DashboardOutlinedIcon />, title: 'Overview', path: '/overview' },
    { icon: <AssignmentIndOutlinedIcon />, title: '경력', path: '/career' },
    { icon: <TopicOutlinedIcon />, title: '활동게시판', path: '/activity' },
    { icon: <ChecklistOutlinedIcon />, title: '할일목록', path: '/todo' },
  ];
  
  return(
      <Menu>
          {items.map((el) =>
            <li key={el.title} onClick={() => { navigate(el.path) }}>
              <AsideMenuItem active={el.title === props.target}>
                //'경력' -->true
                {el.icon}
                <p>{el.title}</p>
                <KeyboardArrowRightOutlinedIcon />
              </AsideMenuItem>
            </li>
            )}
       </Menu>
    );
  
  

📝 target="경력" 을 보내줘야한다

career.js

const CareerPage = () => {
    useAuth();
        return (
            <DashboardLayout target="경력">
                <Title>나의 경력을 관리하세요</Title>
                <p>회사, 직위, 일자를 입력한 후 경력을 추가해 보세요!</p>
                <CareerViewTable />
            </DashboardLayout>
        )
    }

📝 props의 target이라는 key값을 받아온다. (🌟props.targe? -> "경력")

layout.js

const DashboardLayout = (props)=>{

    <Wrapper isOpen={isOpen}>
      <DashboardSidebar isOpen={isOpen} target={props.target}/>  //props.target ->경력
      <MainWrapper>
        <DashboardHeader isOpen={isOpen} setIsOpen={setIsOpen}/>
        <Main>
          {props.children}
        </Main>
        <DashboardFooter/>
      </MainWrapper>
    </Wrapper>
  );
}

export default DashboardLayout;

✏️ target="할일목록"을 써준다

todo.js

import DashboardLayout from "../../components/common/layout";
import { useAuth } from "../../components/hooks/hooks";

const TodoPage = () => {
    useAuth();
    return (
        <DashboardLayout target="할일목록">

        </DashboardLayout>
    );
};

export default TodoPage;

📌 클릭했을때 실행시킬 함수 만들기

li tag가 클릭됬을때, ->onClick()사용

sidebar.js

const navigate = useNavigate();

//path까지 설정해주기
 let items = [
    { icon: <DashboardOutlinedIcon />, title: 'Overview', path: '/overview' },
    { icon: <AssignmentIndOutlinedIcon />, title: '경력', path: '/career' },
    { icon: <TopicOutlinedIcon />, title: '활동게시판', path: '/activity' },
    { icon: <ChecklistOutlinedIcon />, title: '할일목록', path: '/todo' },
  ];

return(
  <Menu>
          {items.map((el) =>
            <li key={el.title} onClick={() => { navigate(el.path) }}>
              <AsideMenuItem active={el.title === props.target}>
                {el.icon}
                <p>{el.title}</p>
                <KeyboardArrowRightOutlinedIcon />
              </AsideMenuItem>
            </li>
           )}
   </Menu>
  );

🐾 sidebar 아이콘 클릭하면 접히게 만들기

state변수를 한개 만들수있다. (true/false)로 구현가능.

layout에 있는 <DashboardHeader isOpen={isOpen} setIsOpen={setIsOpen}/>

layout.js

const DashboardLayout = (props)=>{
  // 사이드바가 열려있는지 닫혀있는지 확인하는 스테이트 변수
   const [isOpen , setIsOpen] = useState(true);
  
  return(
    <Wrapper isOpen={isOpen}>
      <DashboardSidebar isOpen={isOpen} target={props.target}/>
      <MainWrapper>
        <DashboardHeader isOpen={isOpen} setIsOpen={setIsOpen}/> //전달하기
        <Main>
          {props.children}
        </Main>
        <DashboardFooter/>
      </MainWrapper>
    </Wrapper>
  );
}

export default DashboardLayout;

header에 있는 MenuOpenIcon을 클릭했을떄,
onClick()사용

header.js

const DashboardHeader = (props) => {
  // DashboardLayout에서 만든 state변수와 setState함수를 자식인
  // DashboardHeader에서 받아옴
  const { isOpen, setIsOpen } = props;
  
}
return (
  <div onClick={() => { setIsOpen(!isOpen) }} 
    style={{ cursor: "pointer" }}>
        {isOpen ? <MenuOpenIcon /> : <MenuIcon />}
  </div>
  )

sidebar.js

const DashboardSidebar = (props) => {
  
 return (
    <DashboardAside style={{transform : props.isOpen ? '' : 'translateX(-100%'}} >
    </DashboardAside>
   )
 }

css state변수 만들고 props전달해서 사용
layout.styles.js

export const Wrapper = styled.div`
  display: flex;
  border-width: 10px;
  padding-left: ${(props)=> props.isOpen ? '240px' : '0'};
  transition: 300ms;
`;

layout.js

const DashboardLayout = (props)=> {
  // 사이드바가 열려있는지 닫혀있는지 확인하는 스테이트 변수
  const [isOpen , setIsOpen] = useState(true);
  return(
    <Wrapper isOpen={isOpen}></Wrapper>
    )
}
profile
나를위한 노트필기 📒🔎📝
post-custom-banner

0개의 댓글