# 사용자 컴포넌트 추가하기
- 컴포넌트를 어떻게 구성할지 생각한 다음, 사용할 컴포넌트를 나눠준다.
- user를 추가해줘야 하기 때문에 AddUser라는 컴포넌트를 만들고 그 안에 form을 넣어준다.
- lable과 input을 연결할때 리액트에서는 htmlFor을 사용해 연결해준다.

- 나이 값을 받을 input과 제출을 위한 button을 넣어주고, form이 제출 되었을때 실행되어야 하는 함수를 만들기 위해 onSubmit 함수를 form에 달아준다.

- form 이 제출되었을때 새로고침이 되지 않도록 해주는 addUserHandler 함수를 만들어 준 뒤, onSubmit에 연결해준다.

- 이렇게 만든 컴포넌트를 App.js파일에 import해주고 컴포넌트를 넣어준다.

- 다음으로 Card 컴포넌트를 만들어주어 UI 디자인을 넣어준다.
- <Card>컴포넌트로 Adduser 컴포넌트를 감싸주면 되는데, 이렇게 해주고 나서는 Card 컴포넌트에서 {props.children}으로 <Card>컴포넌트가 감싸고 있는 태그들을 모두 가져와준다.


- card부분에 css를 사용해 디자인을 넣어준다.
- module.css를 사용할때는 항상 styles를 import해주고 className에 styles. 를 넣어주는걸 잊지말자.

- AddUser 컴포넌트에서도 Card를 import 해줘야한다.
- Card를 import해준 뒤, 디자인의 향상을 위해 module.css 파일을 만들어 import를 다시 해준다.
- <Card> 컴포넌트에 styles.input의 className을 붙여준다.

- 여기서 중요한 점이 하나 있다. <Card>는 사용자 지정 컴포넌트이지만 내장된 html 컴포넌트가 아니다. 사용자 정의 컴포넌트이기 때문에 그 컴포넌트 안에서 사용하는 props를 통해서만 작동할 수 있다. <label>, <input>, <button> 등은 모두 리액트에 의해 모두 미리 설정된 것으로 props라는 클래스 이름과 함께 작동하고 기본적으로 랜더링 된 html에 적절한 css 클래스를 적용한다.
- 하지만 우리가 만든 사용자 지정 컴포넌트인 Card는 className이라는 속성과 어떻게 작업해야하는지 모른다.
- 그래서 Card 컴포넌트에 가서 className 속성을 받아들여서 처리할 수 있도록 만들어줘야 한다. 우리가 원하는 것은 ClassName의 도움으로 div에 적용하고 있는 css 클래스가 Card클래스에 반영됨과 동시에 Card컴포넌트의 className props에 잠재적으로 들어오는 클래스에도 적용되도록 하는것이다.
- 한마디로 두개의 css를 적용하는 상황인데, 하나는 Card.module.css에서, 또 하나는 props를 통해 잠재적으로 외부에서 들여오는 클래스 인 것.
- 템플릿 리터럴을 추가해서 두 가지 className을 받을 수 있다.

- props.className 같은 경우, 이름은 마음대로 설정 가능하다. 우리가 AddUser컴포넌트에서 <Card className = {styles.input}>으로 className을 사용하기 때문에 여기서도 className을 사용한것이다. 만약 cssClass를 사용했다면 props.cssClass로 대신 넣어주면 된다.
#재사용가능한 button 컴포넌트 만들기
- Button 컴포넌트를 만들기 위해, 새로운 Button.js 파일과 Button.module.css 파일을 만들어준다.
- Button에 className을 연결해주고, 버튼에 type을 설정해준다. 버튼 컴포넌트 외부로부터 값을 받도록 설정할 것이다. type에 할당되는 값은 동적인 값이 된다.
- {props.type}으로 접근할 수 있게 설정하고 값이 지정되지 않을 경우를 대비해 OR 연산자로 button을 설정해준다.
- <button>태그 사이에 있는 컨텐츠를 가져오기 위해서 {props.children}을 넣어준다.

# 사용자 입력 state 관리하기
- 사용자가 입력한 값을 가지와 사용자 목록의 일부로 렌더링을 해주자.
- 우리는 지금 Form에 addUserHandler라는 onSubmit함수를 달아줬고 input창에 들어오는 usename과 age를 수집해서 사용할 것이다. 값을 수집하기 위해서는 state를 사용해야 한다.
- 사용자가 입력하는 것을 state 변수에 저장하는데 그 변수는 리액트에 의해 관리된다.
- 이름과 나이를 담아줄 useState 변수를 만들어준다.

- 다음으로 상태를 변경시켜줄 수 있는 함수를 만들어준다. onChange 와함께 input 박스에 연결해 줄 애들이다.


- 이제 원래 form에 장착해두었던 addUserHandler를 통해 console.log(eteredAge, eteredUsername)을 찍어보면 form이 제출될 때마다 값이 잘 들어오는걸 확인할 수 있다.

#검증추가 및 로직 재설정하기
- 일단 폼이 제출되었을때 username과 age 칸을 비워주는 코드를 작성해보자.
- 이건 간단하게 addUserHandler에 set함수들로 빈칸을 만들어주면된다.

- 하지만 이렇게 해도 input창은 비워지지 않는다. 하지만 콘솔창에는 빈 값들이 계속 찍히는걸 볼 수 있다.
- 여기서의 문제는 input이 현재상태를 반영하지 않았다는 것이다. 사용자가 입력한 경우를 제외하고 어디에서도 바꾸고 싶다면 별 문제가 되지 않는다.하지만 여기서는 폼을 제출하면 바뀌게 하고 싶다.
- 어떻게 해야 input 창에서도 값을 지울 수 있을까?
- 이건 input 태그에 우리가 value 값을 넣어줌으로써 해결이 가능하다. value에 사용자가 입력한 값을 설정해줄 수 있다.
- 이렇게 하면 키 입력으로 변경되는 경우가 아니라 폼을 제출하는 경우에도 현재상태의 스냅샷을 반영하는 입력값을 가질 수 있다.

- 다음으로 유효성 검사를 해보자.
- 폼에 제대로된 값이 들어올때만 addUserHandler가 실행되도록 만들어 줄 것이다.
- 이름, 나이 어느 것도 공백이어서는 안되고 나이도 1보다 작으면 안된다.
- if문을 작성해준다. trim()은 앞뒤에 생기는 공백을 지워준다. length를 체크해서 값이 0이라면 사용자가 아무것도 입력을 하지 않았다는 뜻이 된다.
- return문을 바로 넣어주면 return이 함수를 종료시켜서 그 뒤에 있는 코드들을 실행시키지 않는다.

- 나이가 1보다 작을 경우의 if문도 넣어준다.
- 사실 우리가 input창을 통해 받는 값들은 문자열로 들어온다. 자바스크립트에서는 그냥 작동할수도 있겠지만 그래도 정확한 코드를 위해서 +를 앞에써서 숫자로 자료형을 바꿔준다.

- 이렇게까지 하면 사용자가 값을 입력하지 않았을때는 콘솔창에 어떤 동작도 발생하지 않지만, 값을 입력하면 그 입력한 값이 들어오는 걸 볼 수 있다.
#사용자목록 컴포넌트 추가하기
- 사용자가 입력한 값을 가져오고 출력하는 로직을 가지는 컴포넌트를 두개로 분리해준다.
- 새로운 UsersList 컴포넌트를 만들어준다. 사용자 데이터의 배열 정보를 가져오기 위해서 우리는 props에 의존해서 데이터를 받아와야 한다.
- {props.users}에서 users라는 이름은 마음대로 정해줄 수 있다.

- users에 접근해 모든 user의 데이터를 받아오기 위해서 map()을 돌려준다.
- user는 사용자객체의 배열이고 모든 객체는 속성으로 name과 age를 받는다. 이건 앱을 만드는 개발자가 임의대로 정할 수 있는 구성인 것

- card스타일을 입혀주기 위해 <Card>컴포넌트로 내용을 감싸주고 스타일을 입혀준다.

- 이렇게 UserList를 구성했다면 App.js에 import를 해준다. AddUsers 컴포넌트에서 사용할수도 있겠지만 각각의 컴포넌트는 하나의 기능을 하는게 좋기때문에 따로 분리해서 최상위 root 컴포넌트에 랜더링 해준다.
- 이때 우리는 users라는 배열을 props로 전달했었기 때문에 여기서 users라는 props에 빈배열을 전달해준다.

#State를 통해 사용자목록 관리하기
- 이제 AddUser 컴포넌트에서 만든 버튼을 클릭하면 form 아래에 사용자 목록이 뜨도록 만들어보자.
- 위에서 UsersList에 보내준 빈 배열을 채워주면 되겠지. 새로운 Users라는 객체를 만들어서 배열에 추가해주면 된다. 그리고 UsersList에 추가해주자.
- 이 작업을 위해 Lifting state up(상태끌어올리기) 동작이 필요하다.
- 사용자목록을 관리해야 하는 위치는 Add User 버튼이 클릭되었을때 그 이벤트를 수신해서 AddUser 컴포넌트에 접근 할 수 있어야 하고 또 사용자 배열을 전달하기 위해 UsersList에 접근할 수 있는 위치여야 한다.
- AddUser와 UsersList를 둘다 접근할 수 있는 그 위의 컴포넌트에 상태관리를 끌어올려준다.
- useState를 사용해 새로운 빈배열을 만들어주고 UsersList에 프롭스로 전달해준다.

- 이제 AddUsers 컴포넌트에서 버튼이 눌렸을때 입력된 사용자 이름과 나이를 받아와서 UsersList에 전달해줘야한다. 이건 props로 할 수 있다.
- App.js에 AddUser 컴포넌트에 프롭스를 넣어준다. 이건 이벤트가 발생하는 느낌이니까 on을 넣어 onAddUser로 이름을 지어주자. (반드시 그래야하는건 아니지만)
- 이제 addUserHandler라는 함수를 넣어줄 건데 uName과 uAge를 받아와서 setUserList를 이용해 업데이트를 해줄 것이다. 여기서 이전 목록에 새로운 요소를 첨부해서 상태를 업데이트 할 것이다.
- 이젠상태에 의존해 상태를 업데이트 할때는 안에 콜백함수를 넣어주고 그 안에서 상태를 업데이트할 때 그 함수는 자동으로 이전 상태 중 가장 최신의 스냅샷을 가지고 올 것이다.

- 그리고 새로운 객체를 만들어 받아온 uName과 uAge를 새로운 객체에 넣어준다.
- AddUser컴포넌트에서는 만들어둔 onAddUser 프롭스를 받아와서 실행해준다. 우리는 이게 함수라는걸 알기떄문에 바로 ()를 넣어 실행할 수 있다.

- props.onAddUser()에 enteredUserName과 enteredAge를 전달해주어 form에서 버튼이 클릭될때마다 새로운 값을 UsersList에 전달해주도록 해준다.

- 여기까지 진행하면 새로운 목록안에 입력된 값이 잘 들어가는걸 볼 수 있지만 key 에러를 볼 수 있다

- 우리는 UsersList 목록에서 많은 아이템들을 반복해서 생성하기때문에 key 속성이 필요하다.
- key는 고유한 값을 가지고 있어야 한다. 우리가 만들었던 userList에 id를 추가하고 Math.random().toString()으로 고유한 값을 만들어주자.

- 이제 UsersList 컴포넌트로 가서 <li>에 key 값을 동적으로 할당해준다.

- 이렇게 키를 넣어주면 더이상 에러가 발생하지 않는다.
# Error Modal 컴포넌트 추가하기
- 모달은 겹쳐지는 박스다. UI의 요소가 앱의 다양한 곳에서 사용가능하다.
- UI요소니까 UI 폴더에 새로운 ErrorModal 컴포넌트를 만들어준다.
- 컴포넌트 구성은 아래처럼 해준다. Card 컴포넌트로 감싸주고 똑같이 Button UI를 가져와 넣어준다.

- 이제 모달창에 스타일링을 넣어준다.

- 그럼 이 ErrorModal 컴포넌트는 어디에 넣어줘야 사용이 가능할까? 전체 UI에 영향을 미칠 수 있는 App.js에 넣던가 아니면 실제로 이 모달창을 트리거 하는 AddUser 컴포넌트에 넣어주면 된다.
- 여기에서는 실제로 사용될 AddUser컴포넌트에 넣어준다.

- 그럼 아래와 같이 모달창을 만들수 있게 된다

- 하지만 이 모달창은 동적으로 움직이지 않기 때문에 수정이 더 필요하다.
- 그리고 모달창을 위한 백드롭이 필요하다. 이 모달창과 메인페이지가 겹쳐지는 부분인데 모달창이 떠 있을때는 메인페이지를 사용할 수 없도록 해주는 것이다.
- ErrorModal창에 새로운 <div>를 추가하고 backdrop 스타일링을 넣어준다.

- 그럼 이렇게 모달창이 떠 있을때 메인화면과 상호작용을 끊어줄 수 있다.

#오류 state 관리하기
- 이 모달창을 동적으로 만들어보자. 조건부로 업데이트해주면 되겠지.
- error를 관리하는 state를 만들어주자.
- AddUser컴포넌트에 에러를 관리하는 useState를 만들어준다.

- 그리고 원래 만들었던 enteredUserName과 enteredUserAge 조건부에 setError를 넣어준다.
- 객체형태로 title과 message를 넣어준다.

- 나이관련 조건부에서도 똑같이 setError를 넣어준다.

- 이렇게 오류의 속성들마다 다른 값을 가지게 설정해준다. 오류의 상태스냅샷은 우리가 setError를 호출할 때마다 그 오류를 가지게 된다. 그 다음 전체 컴포넌트가 다시 렌더링된다.
- ErrorModal을 랜더링할때 조건부로 앞에 error를 넣어준다.
- 우리가 위해서 설정해둔 각 에러의 title과 message가 랜더링 되록 넣어준다.

- 하지만 아직 이 모달창을 없앨 수는 없다. ok 버튼을 클릭하거나 배경을 클릭해서 없앨 수 있도록 해보자.
- 이 모달창을 없애기 위해서는 Error를 undefiend 나 null 또는 다른 falsy 값으로 초기화 해주는 것이다.그래서 조건문이 성립되지 않도록 해주면 된다.
- 새로운 함수를 만들어 setError로 값을 null로 바꿔주자

- 이 함수를 실행시키는건 ErrorModal 안에서 가능하다. Error모달이 버튼과 backdrop 요소를 다 가지고 있기 때문이다.
- 둘다 onClick요소를 넣어서 함수를 실행해주자.
- ErrorModal에 onConfirm 프롭스를 전달해준다.

- ErrorModal 컴포넌트에서는 backdrop과 버튼에 onClick 이벤트를 넣어주고 onConfirm을 넣어준다

'Udemy - React완벽가이드' 카테고리의 다른 글
"ref"로 작업하기 (1) | 2023.05.14 |
---|---|
리액트 컴포넌트 스타일링 (0) | 2023.03.15 |
차트 추가하기 (0) | 2023.03.09 |
연도 filter 작동시키기 (0) | 2023.03.03 |
랜더링 리스트 및 조건부 Content (0) | 2023.02.28 |
댓글