패캠 인강/React

[패캠 인강] React 기초 (3)

Je-chan 2021. 8. 11. 22:56

  3-2) input 상태 관리하기 

  이번에 만들어 볼 건 input 창에서 사용자로부터 값을 입력받으면 바로 화면에 입력받은 값이 나오도록 설정하고 초기화 버튼까지 만들겠다. input 도 사용자로부터 입력을 받고 그에 따라 화면에 값이 나오는 동적인 상황이 발생하므로 useState를 사용해줘야 한다. 

 

  수도 코드를 작성하면 다음과 같다

 

1. useState를 통해 input의 기본값과 동적 상태 값을 구조분해 할당으로 가져온다.
2. 동적으로 변화될 값은 input으로 입력받는 내용이어야 한다.
3. 초기화용 버튼을 생성한다.
4. 초기화 버튼을 누르면 변화될 값이 빈 문자열로 바뀐다.

 

 그렇다면 하나씩 작성해보도록 하자. 먼저 1번부터 하면

 

const [text, setText] = useState('')

 

  이렇게 될 것이다. text는 input의 기본값으로 설정할 것이고 setText는 input이 입력받을 때마다 동적으로 어떻게 변화를 줄 것인지 적어줄 것이다. 2번 내용이 바로 setText와 관련된다. 2번 내용을 함수 onChange라는 이름으로 사용하면 다음과 같이 될 것이다. useState의 내부에 들어가 있는 빈 문자열은 text의 값(즉, 기본값)을 의미한다.

 

const inputValueChange = (e) => {
  setText(e.target.value)
}

// 참고로 return에서 input은
// <input onChnage = {inputValueChange} value = {text}></input> 예정

 

  최근 내가 코드 스테이츠에서 DOM과 이벤트 객체를 배워서 지금 e.target.value 가 굉장히 반갑다. e는 event로 사용자로부터 무언가 일어났다는 신호다. 키보드가 눌렸다 떼어졌다는  onKeyUp, 통상 마우스 왼쪽 버튼이 눌렸다는 onClick, 사용자가 input 등에 포커스를 맞췄다는 onFocus, 해당 value에 무언가 변화가 일어났다는 onChange 등 다양한 이벤트들이 있다. 우리는 이 onChange를 input에 넣어주고, input의 value가 바뀌는 onChange 이벤트가 발생하면 위 inputValueChange를 실행할 것이다. 이벤트에는 target이라는 속성이 있는데 이 이벤트가 일어난 객체를 참조한다. 우리 상황으로 따지면 value값이 바뀐 input이 될 것이다. 그리고 target 뒤 속성 value 는 input의 value를 의미하므로 input 안에 들어있는 값을 의미한다. 

 

 

  이제 수도 코드 3), 4)번 reset 버튼을 만들어보겠다.

const onReset = () => {
  setText('')
}

// return에서 button은
// <button onClick = {onReset}>초기화</button> 예정

  onReset 함수가 실행되면 text를 빈 문자열로, 즉 초기화된 상태로 바꿔줄 것이다. 이 함수의 실행 조건은 onClick, 즉 버튼에 마우스 왼쪽 버튼이 눌러질 때 실행된다. 

 

  이 모든 걸 종합하면 다음과 같은 결과물이 나온다 (style은 빼기 위해서 상단 부분 생략했음) 

초기화 버튼까지 잘 눌린다.

 

  3-3) input 여러 개 관리하기 

  이번에 만들어 볼 것은 input 창을 두 개 만들어서 하나는 전하고 싶은 사람의 이름을, 다른 하나는 그 사람에게 전달하는 메세지를 남겨보고자 한다. 즉 input은 두 개를 추가할 것이고, 초기화 버튼도 만들 것이다. 화면에는 좀 변화를 줄 거지만 여기는 input창 두 개를 어떻게 관리할 것인지가 중점이므로 CSS 는 대충 만들어 보겠다. 

 

  일단, 극단의 상황을 가정해서 나중에 input이 100개 만들어지면, 그 100개에 해당하는 것만큼 저 위에 한 방식으로 useState 지정해주고, 함수 각각에 맞게 두 개씩 만들어주고 할 것인가? 1개당 두 개씩 만들어지는 그 함수들이 똑같은 로직이지만 100개 만큼 더 만들어지는 비효율성은 개발자들의 입장에서 용납할 수 없는 짓이다. 그렇기에 우리는 다른 방법을 생각할 건데, 수도 코드처럼 작성해보면 바로 

 

1. input마다 id 값처럼 이름을 지정해주고
2. 그 input마다 useState로 동적 관리 상태에 들어가게 해주고
3. useState로 기본값을 설정해주고
4. onChange 로 변화가 있는 input이 있다면
5. 그 변화가 있는 Input의 이름을 추적해서 그 input의 값에만 함수들이 반응하도록 만들어 주고
6. reset 버튼을 사용하면 모든 input의 내용을 초기화한다.

 

   그럼 이제 차근 차근 시작해보자 1번은 쉬울 것 같다. 그냥 return 되는 input 안에 name 속성을 추가하고 값을 지정해주면 될 것 같다. 첫 번째 input은 응원하는 선수 이름을 적으니까 toName으로 이름을 지어주고, 두 번째 input은 응원 내용을 적는 거니까 cheering이라고 해주자. 나머지는 그냥 원래 하나였을 때 그대로 해주고 특별히 input이 두개니까 구별해주게 placeholder를 사용한다.  

 

<input
  name = "toName" 
  onChange = {inputValueChange} 
  value = {text}
  placeholder = "원하시는 분께"
/>
<input
  name = "cheering" 
  onChange = {inputValueChange} 
  value = {text}
  placeholder = "응원의 메세지를"
/>

  

  순서에는 어긋나지만 4번도 input으로 onChnage = {inputValueChange} 를 통해서 실현시켰다.

 

  2번과 3번은 다 useState 안에서 이뤄지는 것이기 때문에 동시 진행하겠다. 두 수도 코드는 어떻게 해줄까? 각 input마다 useState를 써줘야할까? 그건 너무 비효율적이다. 그래서 우리가 할 것은 useState 기본 값을 지정할 때 객체로 지정해주는 것이다. 일단 만들어 보고 설명하겠다.

 

const [text, setText] = useState({
    toName: '',
    cheering: '',
})

 

  useState 안의 값은 기본값 text에 할당해주는 값이라고 언급한 바 있다. 그런데 input 두 개를 사용한다면, 두 개 다 기본 값을 지정해줘야 한다. 선언된 건 text가 한 개인데 값을 두 개 할당해줘야 하니 객체로 useState 안에서 각 input별로 기본 값을 지정해주는 것이다. 그 때, input의 name을 key값으로 가져와 구분한다. 이렇게 되면 text는 지금 두 개의 input의 기본값이 할당된 것이다.  자 이렇게 2, 3번을 완수했다.

 

  그런데 여기서 문제가 발생한다. text는 현재 객체가 됐다. 그런데 위에서 input에서 기본값을 text라고 지정해줬다. 그렇기에 초기에 출력되는 값은 객체가 된다. 그것을 방지하기 위해서 text를 구조 분해 할당을 통해 나눠주도록 하자. 

 

const { toName, cheering } = text

 

  그리고 이제 다시 input의 초기 값을 각각에 맞게 바꿔주도록 적어주도록 하자. 

 

<input
  name = "toName" 
  onChange = {inputValueChange} 
  value = {toName}
  placeholder = "원하시는 분께"
/>
<input
  name = "cheering" 
  onChange = {inputValueChange} 
  value = {cheering}
  placeholder = "응원의 메세지를"
/>

 

  5번이 가장 문제다. 일단 객체로 input을 나눴기 때문에 inputValueChange 함수가 실행되면 어떤 것의 기본 값을 바꿀 것인지를 파악해야 한다. 우리는 현재 저 각 input의 name을 key값으로 정해줬다. 그렇다면

 

1. setText를 통해서 onChange가 된 엘리먼트의 name값과 input에 사용자가 입력한 value 값을 가져오고
2. text라는 객체에서 가져온 name을 key값으로 갖는 것을 찾아 그것의 value를 바꿔라.

 

  라는 로직으로 작성하면 될 것 같다 코딩해보면

 

const inputValueChange = (e) => {
    
  const { name, value } = e.target // 1. 그 엘리먼트의 name과 value를 갖고 와서

  setText ({ // setText 안의 로직을 통해서 text에 변화를 줄 건데
    ...text, // spread를 통해 text 객체 내부를 다 가져오고 
    [name]: value // 2. 그 text 객체 안에서 엘리먼트의 name과 같은 key값을 찾아 변화된 value로 값을 바꿔라
  })

}

 

  마지막 6번을 코딩해보자면 모든 것을 초기화 하니까 객체를 가져와서 빈 문자열로 value를 다시 할당해주면 될 것 같다.

 

const onReset = () => {
  setText({
    toName: '',
    cheering: ''
  })
}

 

  길고 긴 싸움이 끝났다. 이제 모든 것을 정리해보자면 다음처럼 잘 작동되는 것을 확인할 수 있다.

 

Practice 컴포넌트
Practice 컴포넌트 return 문
App 컴포넌트 return문
출력된 결과물

 

  지금 우리가 작성한 건 그냥 한 지우면 지워지고 저장되지 않는 내용들이다. 다음 시간에는 배열을 이용해서 직접 게시판에 글 올리듯이 작성하는 것을 해보도록 하겠다. 그 전에 내가 완벽하게 이해해야 작성할 수 있겠지만.... 내일의 내가 알아서 잘 공부하겠지 :)

'패캠 인강 > React' 카테고리의 다른 글

React 기초 다지기 (1) - JSX 기초  (0) 2022.01.06
[패캠 인강] React 기초 (5)  (0) 2021.08.27
[패캠 인강] React 기초 (4)  (0) 2021.08.23
[패캠 인강] React 기초 (2)  (0) 2021.08.07
[패캠 인강] React 기초 (1)  (0) 2021.08.03