1-6 React에서 리스트 데이터 수정하기

밥이·2022년 2월 21일
0

React Project

목록 보기
6/14

리스트 데이터 수정하기

배열을 이용한 React의 List에 아이템을 동적으로 수정해보기 With 조건부 렌더링

  1. 수정버튼을 눌렀을때 수정폼이 나타나게 하고, 버튼은 수정완료, 수정취소로 바뀌게 구현.
    (스위치 state를 하나 만들고, toggle함수를 만들어 버튼을 눌렀을때 토글함수 실행)
    ex) 수정상태가 아닐땐(false) 그냥 내용 보여주면되고, 수정 누를땐(true) 수정 폼 보여줌,

  2. 수정폼에 입력하는 데이터들도 React에서 localContent state로 핸들링하게 만들어주기.

  3. <textarea/ >에 value값으로 localContent(수정된값)를 넣어주고, onChange()함수로 setLocalContent() 안에 e.target.value를 적어, 수정 데이터값을 저장하게끔 만들어준다

  4. 수정취소 버튼을 누르면, 수정폼은 없애고 수정, 삭제 버튼이 나타나게 설정

  5. 수정버튼을 눌러서 수정폼이 나오는 순간 원본 데이터 내용이 폼에 나오도록 설정 -> localContent의 기본값을 content로 넣어주면 됨

  6. 근데 이 상태에서 수정을 좀 하고 수정 취소를 누른 후 다시 수정하기를 누르면? 수정이 덜 완료된 값이 그대로 나오게됨

    그래서 수정취소를 눌렀을 때, localContent의 값을 초기화 시켜주는 함수를 만들어야함.
    그럼 취소를 누르고 다시 수정을 누르면 원래의 값이 그대로 나옴

  7. 마지막으로 수정완료 버튼을 눌렀을때 일기 아이템을 수정하도록 만들기

    React의 특성상 데이터는 위에서 아래로,
    이벤트는 아래에서 위로 올라간다고 했었음.

    그럼 App 컴포넌트에 수정하는 함수 기능을 만들어서 props로 DiaryItem 컴포넌트 까지 전달해주면됨

    일단 onEdit()이라는 함수를 만들고, 매개변수로 targetId와 newContent를 받음.
    targetId는 어떤 id를 가진 요소를 수정할지,
    newContent는 어떻게 컨텐츠를 변경시킬건지
    를 받고,
    setData()를 호출을 해서 데이터 값을 변경해주면됨.

    어떻게 바꿔줄꺼냐면!?
    data에 map()함수를 사용해, 모든 data요소를 순회하면서 전달 받은 targetId와 data.id가 같으면? 원본데이터를 ...data불러오고, content는 전달받은 newContent로 업데이트 시켜, 새로운 배열을 만들어서 setData로 전달해줌.

    id가 일치하지 않으면? 수정 대상이 아니므로 그냥 원본 data를 반환하게 해주면됨.

  8. App컴포넌트에 있던 onEdit()함수를 DiaryItem 컴포넌트 까지 전달해주고,
    DiaryItem 컴포넌트에서는 "수정완료" 버튼을 눌렀을때 실행하는 handleEdit() 함수를 만들어주고, onEdit()함수를 호출하여, id와 localContent를 전달해주면 됨.

DiaryItem.js

import { useRef, useState } from "react";

const DiaryItem = ({ onEdit, onRemove, id, author, content, create_date, emotion }) => {

const [isEdit, setIsEdit] = useState(false); // 수정버튼 스위치 state

// toggleIsEdit()이 호출이 되면 setIsEdit()이 되고 !(Not)연산을 통해 isEdit이 true면 false로, false면 true로 바꿔줌
const toggleIsEdit = () => setIsEdit(!isEdit);

// 수정하기 textarea값을 저장하기 위해 state를 만들어줌
// state기본값을 content로 설정하여, 수정눌렀을때 작성했던 내용을 그대로 불러옴
const [localContent, setLocalContent] = useState(content);

const localInput = useRef();

const hadleRemove = () => {
	if (window.confirm(`${id}번째 일기를 삭제하시겠습니까?`)) {
		onRemove(id); // 확인을 누르면 실행
	}
}

// 수정취소를 눌렀을떄 실행
// 수정취소를 누른뒤 수정하기를 눌러도 다시 원래의 값으로 돌아옴
const handleQuitEdit = () => {
	setIsEdit(false); // isEdit을 false로 하여 폼을 없애고
	setLocalContent(content); // 원래있던 input값으로 수정폼 초기화
}

// 수정완료 눌렀을때 
// 해당 id값과, 새로바뀔 컨텐츠인 localContent를 전달
const handleEdit = () => {
	if (localContent.length < 5) {
		localInput.current.focus();
		return;
	}

	if (window.confirm(`${id}번째 일기를 수정하시겠습니까?`)) {
		onEdit(id, localContent); // 해당 id값과, 새컨텐츠 전달
		toggleIsEdit(); // 수정하고 나면 수정폼은 닫아줌
	}
}

return (
	<div className='DiaryItem'>
		<div className='info'>
			<span className='author'>작성자 : {author}  <br />
				감정점수 : {emotion}</span>
			<br />
			<span className='date'>{new Date(create_date).toLocaleString()}</span>
		</div>

		<div className='content'>
			{ // 수정중인 상태면 ? 수정폼을 보여주고, 수정중인 상태가 아니면 : 작성한 컨텐츠를 보여줌
				isEdit
					? (<>
						<textarea
							ref={localInput}
							value={localContent} // 수정내용 기본값 설정
							onChange={(e) => { setLocalContent(e.target.value) }} />
					</>)
					: <>
						{content}
					</>
			}
		</div>

		{ // 수정중인 상태면 ? 수정완료,취소버튼 보이게. 수정중인 상태가 아니면 : 수정, 삭제 버튼 보이게
			isEdit
				? (<>
					<button onClick={handleEdit}>수정완료</button>
					<button onClick={handleQuitEdit}>수정취소</button>
				</>)
				: <>

					<button onClick={toggleIsEdit}>수정</button>
					<button onClick={hadleRemove}>삭제</button>
				</>
		}

	</div>
)
}

App.js

function App() {

const [data, setData] = useState([]);

const dataId = useRef(0);// 어떤 DOM도 선택하지 않고 0이란 값만 들어있음.

const onCreate = (author, content, emotion) => {
	const create_date = new Date().getTime();
	const newItem = {
		author,
		content,
		emotion,
		create_date,
		id: dataId.current
	}
	dataId.current += 1; // newItem이 추가될때마다 0번 id는 1씩 증가해야함
	setData([newItem, ...data]) // 새로운 일기를 추가하면 제일 위로 올라와야하니까. newItem을 앞으로 설정
}															// ...data는 data state의 객체 전부 펼치기

// 삭제버튼 클릭시 해당 요소 id를 targetId로 전달받음
const onRemove = (targetId) => {
	console.log(`${targetId}가 삭제되었습니다.`)
	// 원래있던 일기data.id와 삭제버튼을 누른id의 값이 같으면,
	// 그 값은 제외하고 새로운 배열을 만들어서 newDiaryList에 저장
	const newDiaryList = data.filter((data) => {
		return data.id !== targetId
	})
	setData(newDiaryList); // 삭제한 데이터 배열을 setData()에 상태를 변화시킴
}

// 수정완료 버튼 누를시 실행
// 어떤 id를 가진 일기를 수정할껀지를 targetId로 받고, 
// 어떻게 내용을 변경 시킬건지를 newContent으로 받음
const onEdit = (targetId, newContent) => {
	setData(
		data.map((data) => {
			return data.id === targetId // 전달한 id값이랑 data에 있는 id값이랑 일치하는 id는 '?' 실행
				? { ...data, content: newContent } // id가 일치하면 수정대상이니 수정한 내용으로 업데이트
				: data // 수정 대상이 아니면 그냥 원래 있던값 리턴
		})
	);
};

return (
	<div className="App">
		<DiaryEditor onCreate={onCreate} />
		<DiaryList dummyList={data} onRemove={onRemove} onEdit={onEdit} />
	</div>
);
}

0개의 댓글