[ react ] 포스트 DELETE 하기 (useRef()함수, includes()함수)

Suji Kang·2023년 10월 14일
0

🐾 전체 클릭하기 & 해제하기 ❗️

careerViewTable.js

//전체 체크가 되었는지 아닌지 확인하기 위한 state변수
const [isSelectAll, setIsSelectAll] = useState(false);

//전체선택 (표의 헤더부분에 있는 체크박스 클릭시 실행)
    const onSelectedAll = (e) => {
        console.log(e.target.checked); //클릭하면 true가 나옴 
        setIsSelectAll(e.target.checked); 
      //👉 한번check를 클릭하면 event가 발생하게되어 true, 한번또클릭하면 false
      //👉그 값을 setIsSelectAll변수에 넣어줌.그리고 난후 랜더링됨.
      //그래서 checked됬다가 안됬다가. 하는것을 보여줌        
   }
   
return (
    <tbody>
        {careerList.map((e) => <tr key={e.id}>
            <td><input
                type="checkbox" 
                checked={isSelectAll}
            /></td>
            <td>{
                e.company
            }</td>
            <td>{e.position}</td>
            <td>
                {e.start_date} - {e.end_date}
            </td>
            <td onClick={() => onDeleteCareer(e.id)} style={{
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                cursor: 'pointer'
            }}><DeleteSweepIcon /></td>
        </tr>)}
    </tbody>
)

export default CareerViewTable;    

🐾 체크된것만 삭제하기 ❗️

체크된 녀석을 찾아서 delete해줘.
6개의 행중에서 true인 애들만 삭제해줘. 여기서, 6개모두 기억해줘야함, 그래야 3개가 checked되었는지 몇개가 checked 가 되었는지 알수있다.

여기서 사용할수있는것은 ❓

🐾 UseRef() 함수 ❗️

📝 useRef란 무엇인가❓

알아보기전에, 그전에 잠깐 ❗️

🔎 리액트에서 변수는 크게 3가지

  1. 일반변수
    👉 값이 변경되어도 re-rendering 되지 않는다.
    re-rendering 될때 "초기값"이 나온다.
  2. state 변수
    👉 값이 변경되면 re-rendering 된다.
    re-rendering 되더라도 자기자신의 "값을 기억한다".
  3. ref 객체
    👉 값이 변경되어도 re-rendering "되지 않는다".
    re-rendering 될떄 자기자신의 "값을 기억한다".

똑같은 화면을 다시 그릴필요는 없잖아❓
그래서, state변수는 바뀔때 마다 리렌더링이 되니까🤨 안좋음.. 낭비잖아❗️❗️ 전체 리렌더링안하고.. 바뀐부분만 하고싶은데 ..

🔎 Ref 는 객체 ❗️

객체안에는 key값이 하나 있는데, current가있다. 이것말고는 아무것도 🚫

const MyComponent = () => {
    let a = 10; //일반변수
  
    //re-rendering 되어도 자기자식 값을 기억. 자기자신이 변하면 re-rendering 시키는것 
    let [b, setB] = useState(10); //state변수

   // re-rendering될때 자기 자신의 값을 기억. 자기 자신의 값이 수정되어도 re-rendering 안시키고싶음
    let [c, setC] = useState(10); //state변수

    //re-rendering될떄 자기 자신의 값을 기억. 
    //자기 자신의 값이 수정되어도 re-rendering 안시키고싶음
    let c = useRef(10); //ref객체
    let c = useRef({name:'홍길동', age:10}); //ref객체
    
    let c = useRef(null); 
   //input도 객체니까 .. input에 ref객체를 연결하면 input의 값을 얻어올수있다.

    return (
        <>
            {a}
            {b}
            {c.current}
            <input ref={c}/> 
            <button>a버튼 클릭시 a를 1더한값으로 변경해줌 </button> /*렌더링안됨*/
            <button>b버튼 클릭시 b를 1더한값으로 변경해줌 </button> /*렌더링됨*/
            <button>c버튼 클릭시 c를 1더한값으로 변경해줌 </button>
            <h1>MyComponent</h1>
        </>
    )
}

초기값인 10들이 출력된다.

버튼 a,b,c 를 누르고, 렌더링이 되면❓

일반변수인 a초기값인 10으로 가고,
b와 c는 값을 기억하니까 플러스 1이 되서 11이 된다.


📝 input도 객체니까 .. input에 ref객체를 연결하면 input의 값을 얻어올수있다

const MyComponent = () => { 
    let c = useRef(null); 
   //input도 객체니까 .. input에 ref객체를 연결하면 input의 값을 얻어올수있다.

    return (
        <>
            {c.current}
            <input ref={c}/> 
            <button>c버튼 클릭시 c를 1더한값으로 변경해줌 </button>
            <h1>MyComponent</h1>
        </>
    )
}

c.current가 의미하는것은 input 태그 이고,
input 태그안에는 value, checked 가 있다.

그래서 여기서 우리는 checked를 가져와서 볼꺼야

단순하게 한번 해보자 복잡하니깡❗️❗️❗️

refTest.js

//useRef 익혀보기
import React, { useState, useRef } from 'react';

const RefTestComponent = () => {
    const [a, setA] = useState(0);
    const b = useRef(0);
    let c = 0;

    const showAll = () => {
        console.log('state변수 a: ', a);
        console.log('b.current: ', b.current);
        console.log('일반 변수 c: ', c);
    }

    return (
        <>
            <h1>RefTest Component</h1>
            <h2>state변수 a의 값 : {a}</h2>
            <button onClick={() => { setA(a + 1) }}>state변수 변경</button>
            <button onClick={() => { b.current++; }}>Ref 객체속 current변경</button>
            <button onClick={() => { c++ }}>일반변수 변경</button>
            <br />
            <button onClick={showAll}>변수들 속의 값 보기</button>
        </>
    );
};

export default RefTestComponent;

변수들 속의 값 보기 버튼 클릭하면 👇

일반변수변경 버튼을 3번 눌렀다. 결과값은 다음과 같다 👇 (re-rendering 되지않음)

Ref 객체속 current변경 버튼을 2번 눌렀다. 결과값은 다음과 같다 👇 (re-rendering은 되지않고 저장은됨)

state변수 변경 버튼을 1번 눌렀다. 결과값은 다음과 같다 👇 (re-rendering 되면서 ❗️값이 바뀜 )


import React, { useState, useRef } from 'react';

const RefTestComponent = () => {
    const [a, setA] = useState(0);
    const b = useRef(null);
    let c = 0;

    const showAll = () => {
        console.log('state변수 a: ', a);
        console.log('b.current: ', b.current.checked);
        console.log('일반 변수 c: ', c);
    }

    return (
        <>
            <h1>RefTest Component</h1>
            <h2>state변수 a의 값 : {a}</h2>
            <input 
              ref={b}
              type="checkbox" />
            <button onClick={() => { setA(a + 1) }}>state변수 변경</button>
            <button onClick={() => { b.current++; }}>Ref 객체속 current변경</button>
            <button onClick={() => { c++ }}>일반변수 변경</button>
            <br />
            <button onClick={showAll}>변수들 속의 값 보기</button>
        </>
    );
};

export default RefTestComponent;

b.current 에 내가 만든 input checkbox를 볼수있다.

b.current.checked를 콘솔로 찍어보면,
체크박스를 누를때마다, false, true로 바뀐다.

console.log('b.current: ', b.current.checked);

📌 그런데, checkbox가 여러갠데 그럼 어떻게 하면 여러개를 다룰수있을까?

//useRef 익혀보기
import React, { useState, useRef } from 'react';

const RefTestComponent = () => {
    const [a, setA] = useState(0);
    const b = useRef([]);
    let c = 0;

    const showAll = () => {
        console.log('state변수 a: ', a);
        console.log('b.current: ', b.current.checked);
        console.log('일반 변수 c: ', c);
    }

    return (
        <>
            <h1>RefTest Component</h1>
            <h2>state변수 a의 값 : {a}</h2>
            <input ref={(el) => { b.current.push(el) }} type="checkbox" />
            <input ref={(el) => { b.current.push(el) }} type="checkbox" />
            <input ref={(el) => { b.current.push(el) }} type="checkbox" />
            <input ref={(el) => { b.current.push(el) }} type="checkbox" />
            <input ref={(el) => { b.current.push(el) }} type="checkbox" />
            {/* map으로도 가능 */}
            <button onClick={() => { setA(a + 1) }}>state변수 변경</button>
            <button onClick={() => { b.current++; }}>Ref 객체속 current변경</button>
            <button onClick={() => { c++ }}>일반변수 변경</button>
            <br />
            <button onClick={showAll}>변수들 속의 값 보기</button>
        </>
    );
};

export default RefTestComponent;

b.current.checked를 출력해보면? input tag 6 개가 있는것을 알수있다. 👇

console.log('b.current: ', b.current.checked);


📌 Ref 객체의 current에 태그 객체를 대입하는 방법

const ref객체이름 = useRef(null);
<h1 ref={ref객체이름}>안녕</h1>

👉👉 ref객체이름.current에는 h1태그 객체가 들어가있다.

<h1>안녕</h1>

📌 Ref 객체의 current에 배열을 만들고, 그 배열속에 여러개의 태그 객체를 대입하는 방법

const ref객체이름 = useRef([]); // ref객체이름.current = [] // 비어있는 배열
<h1 ref={(el)=>{ref객체이름.current.push(el)}}>안녕</h1>
<p ref={(el)=>{ref객체이름.current.push(el)}}>반가워</p>
<input ref={(el)=>{ref객체이름.current.push(el)}}/>

👉👉 ref 객체이름.current에는

[<h1>안녕</h1>, <p>반가워</p>, <input/>] 

가 들어있다.


📌 개별행으로 접근하기

 //차라리 전체 체크 되었다 아니다 이분법적인것보다 
 //개별적으로 체크된 요소의 id를 배열에 담아서 express한테 보내서 삭제하도록
 //rendering 할떄 배열안에 있는 행을 그릴때는 체크된채로, 
 //배열안에 없는 행을 그릴때는 체크가 안된채로 그린다.

const [checkedRowId, setCheckedRowId] = useState([]); //체크된 행의 id를 담을 배열. 처음에는 빈배열 (체크된게없음 아직)

 //개별적으로 체크했을떄
    const onSelect = (e, id) => {
        // console.log(e.target.checked);
        // console.log(id);
        //배열에 id를 추가
      setCheckedRowId([...checkedRowId, id]); //기존에 배열에 추가한 id를 넣어줘
    }

return (
        <tbody>
            {careerList.map((e) => <tr key={e.id}>
                <td><input
                    type="checkbox"
                    checked={checkedRowId.includes(e.id)}
                    onChange={() => onSelect(e.id)}
                />
                </td>
            </tr>)}
        </tbody>
        )
}

export default CareerViewTable;

🔎 includes()함수

includes() 메서드는 문자열에 다른 문자열이 포함되어 있는지 여부를 확인합니다.(배열이 특정 요소를 포함하고 있는지 확인하는 메서드)

let fruits = ['apple', 'banana', 'orange', 'grape'];
console.log(fruits.includes('banana')); // true
console.log(fruits.includes('kiwi')); // false

👉 id체크하기

checked={checkedRowId.includes(e.id)}

id가 checked되면 true로 되어서 check가됨


🔎 그런데 check 를 해제했을때도 unchecked가 되야되는데..

const [checkedRowId, setCheckedRowId] = useState([]); //체크된 행의 id를 담을 배열. 처음에는 빈배열 (체크된게없음 아직)

 //개별적으로 체크했을떄
    const onSelect = (e, id) => {
        // console.log(e.target.checked);
        // console.log(id);
        //🌟 체크가 되었으면 배열에 id를 추가
        //체크가 해제되었으면 배열에서 id를 제거
        if (e.target.checked) {
            //배열에 id를 추가
            setCheckedRowId([...checkedRowId, id]); //기존에 배열에 추가한 id를 넣어줘
        } else {
            //🌟 배열에서 id를 제거
            let newCheckedRowId = checkedRowId.filter((e) => e !== id);
            setCheckedRowId(newCheckedRowId);
        }
    }

return (
        <tbody>
            {careerList.map((e) => <tr key={e.id}>
                <td><input
                    type="checkbox"
                    checked={checkedRowId.includes(e.id)}
                    onChange={(event) => onSelect(event, e.id)}
                />
                </td>
            </tr>)}
        </tbody>
        )
}

export default CareerViewTable;

📌 전체선택 (표의 헤더부분에 있는 체크박스 클릭시 실행)

    const onSelectedAll = (e) => {
        // console.log(e.target.checked);
        // setIsSelectAll(e.target.checked);
        if (e.target.checked) { //전체선택이 되었으면
            setCheckedRowId(careerList.map((e) => e.id));
            setIsSelectAll(true); //🌟 ture 일때 
        } else { //체크 해제되어 실행된다면
            setCheckedRowId([]);//배열을 비워준다.
            setIsSelectAll(false);//🌟 false 일때 
        }
        console.log(isSelectAll);
    }
    
   return(
     <tr>
        <th onChange={onSelectedAll} rowSpan={2}>회사명(활동)</th>
        <th rowSpan={2}>직책(활동내용)</th>
        <th colSpan={2}>활동 일자</th>
     </tr>
	 <thead>
              <tr>
                 <th>
                    <input
                    onChange={onSelectedAll}
                    type="checkbox"
                    checked={isSelectAll}
                    />
                 </th>
                 <th>회사명</th>
                 <th>직책</th>
                 <th>일자</th>
                 <th onClick={deleteAll}><DeleteSweepIcon /></th>
             </tr>
     </thead>
   )

이제 마지막으로!! 체크된 id 👉 express로 전달하기 (2:20

선택된 id들 모두 삭제요청

const deleteAll = () => {
        //체크된 행의 id를 가지고 express한테 삭제 요청
        // let res = await axios.delete('/api/career', { data: { id: checkedRowId } });
        checkedRowId.forEach(async (id) => { //삭제가 다섯번 반복이 된다
            try {
                await axios.delete('/api/career', { data: { id: checkedRowId } })
                //첫번째 방법. setCareerList(careerList.filter((e) => (e.id !== id))) //이렇게하면 한번에 마지막 상태를 1번 삭제해준다. 
                setCareerList((cl) => { return cl.filter((e) => e<.id !== id) });
                //2번쨰 방벙. 그때그때마다 삭제해주고 state변수 바뀌었으니 다시 리렌더링 하고. 데이터가 좀더 느리다는 단점이 있다. 
                alert('삭제 완료!')
            } catch (err) {
                console.log(err)
                alert('삭제 하는 도중 문제가 발생하였습니다. ');
            }
        });
    }
  return(
     <>
        <th>회사명</th>
              <th>직책</th>
              <th>일자</th>
              <th onClick={deleteAll}><DeleteSweepIcon /></th>
      </>
  )
} 

삭제한번에 변경하기

반복횟수만큼 filter()함수를 써야한다.

효율적이지 않기 때문에, 반복문 forloop 사용

const deleteAll = async () => {
  //기본 careerList 에서 삭제한 요소들을 제외한 배열 만들기
        //체크된 행의 id를 가지고 express한테 삭제 요청
        // let res = await axios.delete('/api/career', { data: { id: checkedRowId } });
        let cpy = careerList;

        try {
            for (let i = 0; i < checkedRowId.length; i++) {//삭제가 다섯번 반복이 된다
                let id = checkedRowId[i];
                await axios.delete('/api/career', { data: { id: checkedRowId } })
                cpy = cpy.filter((row) => row.id !== id);

                //첫번째 방법. setCareerList(careerList.filter((e) => (e.id !== id))) //이렇게하면 한번에 마지막 상태를 1번 삭제해준다. 
                // setCareerList((cl) => { return cl.filter((e) => e.id !== id) });
                //2번쨰 방벙. 그때그때마다 삭제해주고 state변수 바뀌었으니 다시 리렌더링 하고. 데이터가 좀더 느리다는 단점이 있다. 
            }
            setCareerList(cpy); //두번째 반복이 다 끝나면,  setCareerList(cpy)로 "한번"에 마지막 상태를 5번 삭제해준다.
        } catch (err) {
            console.log(err)
            alert('삭제 하는 도중 문제가 발생하였습니다. ');
        }
    }
profile
나를위한 노트필기 📒🔎📝

0개의 댓글