이전 수업 말미에 말씀드린 작업을 시작해 보겠습니다
입력값이 있는 NewTask 컴포넌트에서
시작해 보겠습니다
이제 해당 버튼을 클릭했을 때
사용자가 입력한 값을
추출해야 합니다
그것은 참조(ref)를 사용하면 됩니다
하지만 또 버튼을 클릭했을 떄
입력한 값을 지우고
비어있는 칸으로 만들어 보겠습니다
이것 또한 참조를 사용할 수 있지만
그것은 리액트가 DOM과 DOM 업데이트를
담당한다는 개념을
조금 위반하는 일이 됩니다
그러니, 실습을 위해서 이번에는
상태(state)를 사용해보겠습니다
리액트에서 useState를 가져오겠습니다
그리고 여기는 enteredTask와
SetEnteredTask 상태 업데이트 기능이 있습니다
그 다음 여기 handleChange라는 함수를 추가하여
OnChange 속성을 추가하는 방식으로
이 입력값에 연결시키겠습니다
그러면 값으로 handleChange가 나옵니다
이전에 배운 것처럼
여기 이벤트 객체가 있습니다
여기엔 이 이벤트의 대상을 포함하는데
그것이 이 입력값입니다
그러면 여기에 입력된 값이
포함됩니다
setEnteredTasks를 불러와서 event.target.value를 전달함으로써
이 상태를 업데이트시키면
입력한 값을 이 상태의
새로운 값으로 저장할 수 있습니다
그러면 이 입력창에
EnteredTask 문자를 추가하여
이 양방향 바인딩을 마무리 할 수 있습니다
그러면 입력되는 각 문자가 모두 입력됩니다
이제 확인할 부분은 이 버튼을 클릭했을 때
이 할 일에 대한 정보가
보관 될수 있는 곳에 보내지는 것입니다
그리고 그 자리는 당연히 앱 컴포넌트 안이 됩니다
여기에 모든 프로젝트가 보관되기 때문에
프로젝트들과 연관된
할 일 목록들도
이곳에 보관되는 게 좋습니다
이 말은 곧
이 할 일과 함수들을
앱 컴포넌트의 할 일 상태를
업데이트하기 위해
여러 겹의 컴포넌트를 통해 전달해야 합니다
이미 여기 앱 컴포넌트에서는
많은 상태관리를 하고 있습니다만
다음 섹션에서는
이 앱 전체를 아우르는
상태 관리법을 새로 배울텐데
조금 더 쉽고 편리할 것입니다
하지만 그 방식을 이해하기 위해선
먼저 지금 사용할 방식을 이해하는 것이 중요합니다
그리고 이 방법을 이해하는 것은
번거로울 수 있습니다
이미 보고 계시듯이
앞으로 할 일들을 관리하면서 더 확실하게 느끼실 것입니다
여기 앱 컴포넌트를 관리하는 이 상태에서
별도의 배열을 수행하도록 하겠습니다
그러니 여기에 할 일을 추가하려면 각각 다른
함수가 필요합니다
예를 들어 할 일 추가와
할 일 삭제도 각각 필요합니다
이 앱에서 이게 모두 가능해야 하기 때문입니다
이 상태와 함수에 대해서는
여기 이 컴포넌트의 할 일을 관리할 것이라고
먼저 언급을 하고 이후에 다시 돌아오겠습니다
그렇게 해서
NewTask 컴포넌트로 돌아가겠습니다
여기에 이 버튼이 있죠
이 할 일 추가 버튼은
나중에 클릭할 예정입니다
지금은 여기에 함수를 추가해서
이름을 HandleClick이라고 짓고
이렇게 onClick 속성을 사용하여
이 버튼에 연결시켜 주겠습니다
그리고 handleClick 안에서 두 가지 일을 해야 합니다
먼저 입력된 값을 앱 컴포넌트로
보내야 하고
그 다음에는 이 입력란을 빈 칸으로 리셋시켜야 합니다
이렇게 하면 할 일 추가 버튼을 눌렀을 때
입력란이 비워지게 됩니다
리셋 작업부터 시작하겠습니다
SetEnteredTask를 빈 문자열로 설정합니다
그리고 이제 입력된 값이 앱 컴포넌트쪽으로 가는 것도
신경을 써야 합니다
그러기 위해서 여기 보시면 이미 함수가 있습니다
이제 이 handleAddTask 함수를
NewTask 컴포넌트에 추가하겠습니다
이 NewTask 컴포넌트는
할 일컴포넌트에 있기때문에
그 컴포넌트 쪽으로 들어가야 합니다
그리고 그 할 일 컴포넌트는
SelectedProject 컴포넌트에 있기때문에
이쪽으로도 가야합니다
이런것을 프로퍼티 내리꽂기(prop drilling)이라고 합니다
그리고 이 내리꽂기를 없애는 법은
다음 섹션에서 다루겠습니다
지금은 문제를 이해해보기 위해서
일단 한 번 해 보고, 이 속성을
이 모든 컴포넌트로 전달시키겠습니다
그러니 앱 컴포넌트에서부터 시작하여
HandleAddTask를 값으로서
SelectedProject 컴포넌트에 전달하겠습니다
여기에 새로운 속성을 추가함으로써 가능합니다
이름은 onAddTask로 하겠습니다
이제 이것은 handleAddTask를
값으로 받습니다
여기에 또 onDeleteTask를 추가하여
handleDeleteTask와 같게 하겠습니다
왜냐하면 이것은 마지막에
이 컴포넌트 안에서 제동되기 때문입니다
정확하게 말하면
이 컴포넌트 안에서가 아니라
이 컴포넌트 내부에 사용된 컴포넌트에서부터 입니다
그러니 이 속성들을
이 컴포넌트를 통하여 전달시키겠습니다
다음으로는 SelectedProject로 가서
새로 추가된 onAddTask와 onDeleteTask를
불러옵니다
이미 언급했듯 여기서 필요한 내용은 아닙니다
다만 할 일 컴포넌트로 전달해야 합니다
그러니 여기에 onAdd 속성을 추가하여
OnAddTask와 동일하게 합니다
그리고 저는 조금 다른 이름을 써서
헷갈리지 않게 하겠습니다
그리고 onDelete 속성을 추가하고
이것은 방금 추가된 onDeleteTask 속성을 받습니다
그렇게 해서
이제 할 일 컴포넌트로 갑니다
그리고 거기서 구조 분해(destructure)를 사용하여 방금 추가한
OnAdd와 onDelete를 얻습니다
OnDelete은 나중에 할 일을 출력할 때
여기에 필요할 것입니다
OnAdd는 NewTask로 전달하겠습니다
그러니 NewTask에 onAdd 속성을 추가하고
여기있는 onAdd 속성에 값으로
추가시킵니다
마침내 프로퍼티 내리꽂기를 마쳤습니다
NewTask 안에서 onAdd를 구조 분해하여
추출합니다
그리고 마지막으로
여기 handleClick에 onAdd를 불러와서
EnteredTask 값을 전달하면
이용자가 입력한 값이 onAdd로 가는 것입니다
그러면 마지막에
Task 컴포넌트에 있는 onAdd 속성으로 오게 됩니다
결국 SelectedProject 컴포넌트에 있는
OnAdd 속성이며
그리고 마지막으로 이것은 앱 컴포넌트에 있는
HandleAddTask입니다
그러니 여기서는
할 일 text를 입력값으로 가정하고
이것으로 상태를 업데이트 할 수 있습니다
그리고 상태를 업데이트 할 때는
프로젝트를 추가할 때 썼던
방식을 똑같이 사용하겠습니다
할 일 추가와 아주 유사하기 때문입니다
복사해서 handleAddTask에 추가하고
이제 대신 할 일 ID를 생성해야 합니다
그리고 여기 새로 생성되는 newTask 객체는
text라는 속성만 있어서
여기서 오는 문자를 보관하게 됩니다
그러니 이 text는 이 text 속성에 저장된
이 text입니다
이제 ID가 생기는데, 이것은 할 일 ID입니다
여기와 동일하게 랜덤으로 생성되는 ID입니다
추가적으로 이 할 일이 속한 프로젝트의 ID도
저장되어야 합니다
그것은 여기 prevState에서 가져올 수 있습니다
왜냐하면 그것이 지금 선택된 프로젝트이기 때문입니다
프로젝트가 선택되어야지만 할 일을 추가할 수 있습니다
그러니 prevState에서 그것을 가져오고
거기서 이 selectedProjectID를 사용합니다
이제 여기 할 일 배열에
이 newTask를 추가하겠습니다
우선 기존의 할 일들을 모두 펼처놓아
하나의 할 일도 잃지 않게 하겠습니다
그리고 그 newTask를 마지막 요소로 추가합니다
아니면 첫 번째 요소로 추가하여도 됩니다
각자가 선호하는 방식으로 하면 됩니다
그리고 여기있는 프로젝트들은 건드리지 않고
이 객체로 카피하여
할 일만 수정하겠습니다
여기 selectedProjectID도 업데이트하지 않겠습니다
할 일이 추가되었다고 해서
프로젝트 선택이 취소되는 일이 없게 하기 위해서입니다
대신에 이렇게 하겠습니다
새로운 할 일만 추가하고 멈추겠습니다
이제 이것으로
이제 할 일을 추가하기 위해서 필요한 것은
이론상 모두 완료했습니다
하지만 당연히 여기 할 일 컴포넌트에
할 일들이 제대로 출력되는지 확인해야 합니다
그래서 이 쪽에 속성이 한 가지 더 필요합니다
이 컴포넌트가 렌더링되는 프로젝트에
속하는 할 일들을 가져와야 합니다
그러니 여기에 이제 할 일 배열이 있고
이 배열을 사용해서
이 문단이나 목록을 조건부로 출력할 수 있습니다
그러니 만약 task.length가 0과 같다면
그러니까 아직 이 프로젝트에 할 일이 없다면
이 문단을 출력할 것입니다
아니면 task.length가 0보다 클때
이 UL을 출력하게 됩니다
그리고 이 UL에는
실제 할 일들이 출력되어야 합니다
간단히 목록 항목에 매핑시키면 됩니다
이전에 몇 번 했던 것과 같이
여기에 할 일이 나오고
그 다음 목록 항목을 출력시켜서
그 안에 할 일 텍스트가 보여지게 합니다
추가로 여기에 키(key)를 넣어서
ID를 task로 설정합니다
이제 이 task.text를 span으로 감싸겠습니다
왜냐하면 그 다음에
여기에 버튼을 하나 넣기 위해서입니다
이 버튼을 사용하여 clear, 그러니까
할 일을 삭제하게 될 것입니다
이제 형식 편집을 위하여
이 UL에 클래스를 추가하겠습니다
모든 방향으로 패딩(padding)을 더하고
윗부분에 여백을 더하고
그리고 모서리를 둥글게 하겠습니다
그리고 배경색으로
이것을 구별하기 쉽게 하겠습니다
아주 작은 변화지만 그래도 괜찮습니다
그리고 LI에는
마찬가지로 클래스를 추가하겠습니다
Flexbox를 사용하여 이 버튼이
이 텍스트와 같은 줄에 자리하게 합니다
둘 사이에 공간을 좀 추가하기 위해서
Justify-between을 사용하여
서로 좀더 멀리 위치시키겠습니다
그리고 모든 목록 항목 위 아래로
여백을 추가하고
마지막으로 이 버튼에
간단하게 짙은 회색을 주겠습니다
그리고 롤오버(hover) 했을 때는
빨간색이 되도록 하겠습니다
이 때 할 일이 지워지기 때문입니다
프로젝트를 지우는 버튼에도
똑같이 할 수도 있겠지만
일단은 할 일 삭제 버튼에만
적용하겠습니다
그렇게 해서 할 일을 출력하고 있지만
이 task 속성이 실제로 값을 받고있는지
확인해야 합니다
그러기 위해서 다시 앱 컴포넌트로 돌아가
여기 이 할 일
이 상태에서 관리하고 있는 것들을
모든 컴포넌트를 거쳐 할 일 컴포넌트로 전달해야 합니다
그러니 SelectedProject로 가서
할 일 속성을 추가합니다
이 프로젝트에
할 일 컴포넌트가 있기 때문입니다
그리고 projectsState.tasks의 값을
이 할 일 속성의 값으로 설정합니다
그리고 SelectedProject 안에서
새로 추가된 할 일 속성을 추출하여
여기에 추가된 할 일 속성의 값으로
할 일 컴포넌트로 전달하겠습니다
오늘 작업은 할 일이 아주 많습니다
이제 마지막 단계입니다
여기 SelecteProject에
속성으로 받는 이 할 일들을
할 일 컴포넌트의 할 일 속성값으로
전달하겠습니다
그러면 이제 이 할 일 설정이 끝났습니다
이제 여기서 저장을 하고
새로운 프로젝트를 만들어 보고
아무 날짜나 넣겠습니다
그 프로젝트를 선택하고 할 일을 추가하겠습니다
그러면 여기에 잘 나오고 있습니다
그리고 여러 할 일을 추가할 수 있고
그리고 여기 버튼도 있습니다
이제 이 삭제(Clear) 버튼이
작동하는지만 확인하면 되겠습니다