개발🐕/React

[React Project: 간단한 일기장(5)] 배열사용해서 데이터 조작하기3- 데이터 삭제및 수정

SU_VIN 2023. 1. 3. 22:37
반응형

 

 

 

한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지 - 인프런 | 강의

개념부터 독특한 프로젝트까지 함께 다뤄보며 자바스크립트와 리액트를 이 강의로 한 번에 끝내요. 학습은 짧게, 응용은 길게 17시간 분량의 All-in-one 강의!, - 강의 소개 | 인프런...

www.inflearn.com

 

 

 

 

 

[React Project: 간단한 일기장(4)] 배열사용해서 데이터 조작하기2- 데이터 추가

한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지 - 인프런 | 강의 개념부터 독특한 프로젝트까지 함께 다뤄보며 자바스크립트와 리액트를 이 강의로 한 번에 끝내요. 학습은 짧게, 응

su-vin25.tistory.com

이어서...


 

  1. 리스트 렌더링(조회)
  2. 데이터 추가
  3. 데이터 삭제
  4. 데이터 수정

3. 데이터 삭제

데이터 삭제는 앞서서 했던 데이터 추가와 아주 유사하다!!

 

우선 DiaryItem에 content 밑 부분에 삭제 버튼을 만들어주자

그다음 onClick 리스너를 달아놓자 id 도 한번 찍어보면 이 일기 아이템의 Id 가 찍힌다이 id로 삭제로직을 짜볼 것이다

<div>
    <button onClick={()=>{
    	console.log(id);
    }}>삭제하기</button>
</div>

 

 

 

생각을 해보자 삭제 버튼을 누르면 현재 일기의 아이템이 들어있는 App.js 에 있는 [data, setData]의 data값 중

내가 삭제할 일기를 뺀 나머지 일기들만 새로 만들어줘야 한다 

그러므로 우리는 App.js에서 data에 손을 대야 한다 바로 onDelete 함수를 만들어보자

 

const onDelete= (targetId)=>{
	console.log(`${targetId}번의 일기가 삭제되었습니다`)
}

함수만 만들어 두면 뭐 하나 prop으로 넘겨줘야지 그치그치

onDelete함수를 App.js 에서 생성하였으니 이 함수가 필요한 DiaryItem까지 전달하려면

DiaryItem의 부모 컴포넌트인 DiaryIist를 거쳐서 보내야 한다 DiaryIist에는 onDelete함수가 필요하지도 않은데 말이다

이것은 props drilling이라 한다

 props drilling ↓

더보기

Prop Drilling 은 props를 오로지 하위 컴포넌트로 전달하는 용도로만 쓰이는 컴포넌트들을 거치면서 React Component 트리의 한 부분에서 다른 부분으로 데이터를 전달하는 과정입니다.

 

솔직히 많아도 문제는 없다 하지만 점점 깊어질수록  해당 props를 추적하기도 어렵고 유지보수에도 매우 좋지 않음!

뭐 어쩔 수 없으니 보내보자

App.js

DiaryList에 prop으로 보내주고

DiaryList.js

DiaryList에선 prop 받아서 다시 DiaryItem으로 보내주고

DiaryItem.js

마침내 필요한 곳까지 왔다

그럼 바로 사용해 보자

<div>
    <button onClick={()=>{
        if(window.confirm(`${id}번째 일기를 삭제하시겠습니까?`)){
            onDelete(id);
        }
    }}>삭제하기</button>
</div>

버튼을 눌렀을 때 확인창이 뜨게 해 주고 그다음 onDelete함수에 해당 일기의 id를 인자로 보내준다

그럼 onDelete에서 받아보자

 

여기선 js의 배열내장함수 중 하나인 filter를 사용해 해당 번호를 제외한 배열을 다시 생성해볼 것이다

const onDelete = (targetId)=>{
	console.log(`${targetId}가 삭제되었습니다`);
	const newDiaryList= data.filter((it)=>it.id!==targetId);
	setData(newDiaryList);
}

현재 data배열에 filter을 하여 해당 id와 같지 않은 배열들만 새로운 배열에 담아서

setData함수에 넘겨줬다

 

잘 삭제되는 걸 볼 수 있다 ㅎㅎ

 


4. 데이터 수정

마지막 데이터 수정을 해보자

로직을 생각해 보자면 이 수정은 삭제와 마찬가지로 DiaryItem에서 일어나야 할 것이다! 이미 써진 일기를 수정해야 하는 것이기

때문에 그러므로 삭제버튼 옆에 수정버튼 하나 만들어주자뭐 위의 방법과 같으므로 따로 설명은 안 하겠다!

버튼을 생성하였다!

 

그럼 수정하기 버튼을 클릭하면 어떤 상황이 일어나야 할까?

ㅇㅇㅇㅇㅇ라고 써진 본문대신에 새로운 일기를 수정할 수 있는 폼이 나와야 할 것이다!

이것을 다루기 위해 새로운 state를 생성해 보자

const [isEdit,setIsEdit]=useState(false);

boolean값을 주고 true일 때 수정 중인 것이다

 

그리고 이것을 껐다 켜줄 toggle함수도 만들어보자 

const toggleIsEdit=()=>setIsEdit(!isEdit);

현재상태에 not연산자를 사용해 상태를 반전시켜 준다

그리고 이것을 수정하기 버튼이 눌리면 실행되게 onClick이벤트를 이용해 달아 준다

 

그럼 수정 중일 때와 아닐 때 바뀌어야 할 부분은? 바로 content부분이다 

이<div> 부분을 수정해 보자

<div className="content">
    {isEdit?<>
        <textarea/>
    </>:<>{content}</>}
</div>

삼항연산자를 사용해 수정 중일 때의 렌더링 할 요소 우선 textarea 넣어주고, 아닐때의 렌더링할 요소를 넣어준다 아닐 때는 기존의 값이므로 {content} 그대로 넣어주자

 

그럼 수정하기 버튼을 누르면 새로운 textarea가 생기는 걸 볼 수 있다

이 수정할 때의 textarea에 쓰는 글들도 state를 사용해 다뤄보자

const [localContent,setLocalContent] = useState(content);

초기값을 빈 문자열이 아니라 현재의 content를 주는 이유는 

보통 글 수정을 할때 기존의 글에서 수정을 시작하기 때문!

그 후 맨 처음 다뤘던 사용자 입력처리에서 했던 거처럼 태그에 value를 넣어주고 onChange를 이용해 조작해 보자

<textarea value={localContent} onChange={(e)=>setLocalContent(e.target.value)}/>

오케이

 

그럼 content부분만 바뀌어야 할까?

아니다 수정하기 버튼을 눌렀을 때 버튼들의 상태도 바꿔줘야 한다

<div>
    {isEdit?<><button>수정 취소</button>
            <button>수정 완료</button></>:
            <><button onClick={handelDelete}>삭제하기</button>
            <button onClick={toggleIsEdit}>수정하기</button></>}

</div>

위와 같은 삼항조건식을 이용해 수정 중이라면 수정취소와 수정완료 버튼을 아니라면 그대로 둔다

 

여기서 한 가지 문제가 발생한다

수정하기를 눌러서 수정을 한 후 수정취소를 누르고 다시 수정하기를 누르면 이전의 값이 그대로 남아있다

수정 부분의 textarea의 상태변화함수인 setLocalContent를 초기화를 안 해줬기 때문이다

//수정상태에서 나간다
const handleQuitEdit = ()=>{
    setIsEdit(false);
    setLocalContent(content);
}

수정취소를 누르면 발생할 핸들러를 하나 만들어주자

수정상태를 수정 중이 아님으로 바꿔 주로 setLocalContent에 기존의 content를 넣어주면 된다

수정취소 버튼에 달아주자 이건 이제 할 수 있지요?

 

이제 남은 건 수정완료 버튼을 눌렀을 때 localContent의 값이 setData의 content값으로 변경되면 된다!

그럼 다시 App.js까지 올라가 수정하는 함수를 만들어주자

const onEdit = (targetId,newContent)=>{
	setData(
  		data.map((it)=>it.id===targetId?{...it,content:newContent}:it)
	)
}

매개변수로는 targetId와 수정할 newContent를 받아오고 

data.map을 하여 수정할 아이디가 맞으면 우선 그 일기를 스프레드 연산자로 다 가져온 다음에

content부분만 newContent로 업데이트해주면 된다!

 

아까 했듯이 prop으로 DiaryItem까지 넘겨준다

이것이 조작해 보자

const handleEdit = ()=>{
    if(localContent.length<5){
        localContentInput.current.focus();
        return;
    }

    if(window.confirm(`${id}번째 일기를 수정하시겠습니까?`)){
        onEdit(id,localContent);
        toggleIsEdit();
    }

}

처음 사용자 입력에서 했듯이 본문의 길이가 5가 넘어가지 않으면 useRef를 사용해 focus를 준다

(줘야 할 부분은 바로 textarea!!)

다음 안내창을 띄우고 onEdit함수를 호출한 후 수정상태를 바꿔주면 끝!

이 함수도 그랬듯이 수정완료 버튼에 달아주면 됩니다!!

 

 

잘 돌아가용!


..💬

리액트는 데이터 흐름이 단방향이고 이벤트는 아래서 위로 데이터는 위에서 아래로 

이러한 특성 때문에 props drilling이 발생할 수 있음!

 

3번에 나눠서 데이터 조작하는 법을 알아봤다! 확실히 state ref prop 다루는 게 익숙해졌다 

더 힘내잣!

반응형