-
34일차 - 리액트 입문 (1), 불변성AI 솔루션 개발자과정(Java, Python) 2022. 11. 24. 17:58
props
props 는 properties 의 줄임말이다.
우리가 어떠한 값을 컴포넌트에게 전달해줘야 할 때, props 를 사용한다.
props 의 기본 사용법
App 컴포넌트에서 Hello 컴포넌트를 사용 할 때 {name} 이라는 값을 전달하려면 다음과 같이 작성한다.

Hello.js에서 Hello 컴포넌트의 매개변수를 props로 지정한다.
props는 객체 형태이며, name을 조회하려면 {props.name}을 지정해 주면 된다.

여기에 color값을 지정하여 폰트 색상을 변경하려면 다음과 같이 추가한다.


속성이 추가될 때마다 props를 입력하여 조회를 하는데,
함수의 파라미터에서 비구조화 할당(구조 분해)문법을 사용하면 조금 더 코드를 간결하게 작성 할 수 있다.

defaultProps 로 기본값 설정
컴포넌트에 props 를 지정하지 않았을 때, 기본값을 설정하고 싶으면 컴포넌트에 defaultProps 라는 값을 설정하면 된다.

컴포넌트 바깥에 컴포넌트.defaultProps 로 설정한다.
컴포넌트 내부에 사용할 때는 static defaultProps = {}로 사용한다.
props.children
컴포넌트 태그 사이에 넣은 값을 조회하고 싶을 땐, props.children 을 조회하면 된다.
props.children을 사용하는 새로운 컴포넌트 Wrapper.js를 만든다.

App.js에 Wrapper 태그 내부에 Hello 컴포넌트가 있음에도 브라우저에는 보여지지 않는다.


Wrapper 태그 내부의 내용이 보여지게 하기 위해서는 Wrapper에 props.children을 렌더링해주어야 한다.
props를 생략하여 매개변수로 children, 속성값으로 children을 써도 된다.
조건부 렌더링
조건부 렌더링이란, 특정 조건에 따라 다른 결과물을 렌더링 하는 것이다.
JSX에서 null, false, undefined를 렌더링하게 된다면 아무것도 나타내지 않는다.

App.js에서 Hello컴포넌트에 isSpecial이라는 props를 설정한다.
true는 자바스크립트 값이기 때문에 중괄호로 감싸준다.
Hello 컴포넌트에서는 isSpecial이 true냐 false냐에 따라서 컴포넌트의 좌측에 * 표시를 보여주도록 한다.
이를 처리하는 가장 지본적인 방법은 삼항연산자를 사용하는 것이다.

삼항연산자을 이용하여 코드를 작성하고 브라우저를 확인하면 컴포넌트 좌측에 *이 생겼다.
isSpecial의 설정값은 true이기 때문에 *이 나타난 것이고, isSpecial이 false가 된다면 표시되지 않는다.
삼항연산자를 사용한 조건부 렌더링은 주로 특정 조건에 따라 보여줘야 하는 내용이 다를 때 사용한다.
지금은 내용이 달라지는 것이 아닌 단순히 특정 조건이 true냐 false냐에 따라 보여주고 숨겨주는 것이기 때문에 && 연산자를 사용하여 처리하는 것이 더 간편하다.

코드가 이렇게 수정된다면, isSpecial이 true일 때 *을 보여준다.
이는 단축 평가 논리 계산법으로 A && B 일때 A가 ture라면 결과는 A가 된다. false라면 B가 된다.
단축 평가 논리 계산법은 처음 false를 반환하게 되면 그것이 결과값이 되고, false가 없거나 둘다 false인 경우 뒤에 오는 요소가 결과값이 된다.

또한 App.js에서 isSpecial의 불리언값(true , false) 입력을 생략한다면, true로 설정한 것으로 간주한다.
isSpecial 은 isSpecial={true}와 동일한 의미이다.
useState
컴포넌트에서 동적인 값을 상태(state)라고 부른다. 리액트에는 useState라는 함수가 있고, 이것을 사용하면 컴포넌트에서 상태를 관리 할 수 있다.

버튼2개와 숫자를 표기할 h1태그 하나를 가지는 Counter.js 를 만든다.
이것을 버튼을 누르면 숫자가 바뀌는 컴포넌트로 만들것이다.

App.js에서 Counter를 렌더링한다.

브라우저에는 이런 UI가 보여질것이다.
다시 Counter로 가서 버튼이 클릭되는 이벤트가 발생했을 때, 특정 함수가 호출되도록 이벤트 설정을 한다.

버튼이 클릭되었을 때 콘솔에 수치가 나오도록 설정했다.
버튼과 함수는 onClick 이벤트로 연결하였다.
주의사항은 함수형태를 넣어야한다. onIncrease와 onDecrease는 함수를 상수에 저장한것이다.
이벤트 onClick에 onIncrease() 같은 함수호출문을 넣으면 안된다.
이벤트 핸들러에는 함수호출문을 사용하면 안된다.

첫 줄의 {useState}는 리액트 패키지에서 useState 함수를 불러온다.
네번째 줄에 작성된 구문은 useState를 사용할 때 상태의 기본값을 파라미터로 넣어서 호출해준다.
첫 원소는 현재 상태, 두번째 원소는 세터함수이다.

원래는 이러한 형식으로 선언해야 하지만, 배열 비구조화 할당을 통하여 축약한 것이다.

h1태그에는 현재 상태를 나타내도록 수정한다.

실행하면 클릭하는 버튼에 따라 상태가 변한다.
함수형 업데이트
세터함수는 파라미터로 전달 받은 값을 최신 상태로 설정해준다.
지금은 세터함수를 사용 할 때, 업데이트 하고 싶은 새로운 값을 파라미터로 넣는 방식을 사용중이다.
그 대신 기존 값을 어떻게 업데이트 할 지에 대한 함수를 등록하는 것으로도 값을 업데이트 할 수 있다.

세터함수를 사용할 때 값을 업데이트하는 함수(화살표 함수. 람다)를 파라미터로 넣었다.
이것을 함수형 업데이트라 하는데, 이는 주로 컴포넌트를 최적화 할 때 사용한다.
input
사용자가 입력 할 수 있는 input 태그

위의 예제와 비슷하게 useState 함수를 사용하여 input의 onChange 이벤트를 사용하는 코드이다.
useState의 원소로 상태를 나타낼 text와 setText 함수를 받는다.
setText는 input에 사용자가 입력을 하게되면 onChange이벤트가 발생하여 value 값을 useState의 text로 업데이트한다. value값을 지정해야 상태가 바뀌었을 때 input의 내용도 업데이트가 된다.
이 text를 b태그와 input태그에 연결하면, 초기화 버튼을 눌렀을 때 동기화되어 같이 초기화 된다.
여러개의 input 상태 관리하기

<- input 상태와 세터함수를 설정한다.
input은 2개이기 때문에 절차가 복잡해진다.
inputs에는 input들의 name값을 지정하고 있다.
<- input에서 onChange이벤트가 발생했을 때 타겟의
value와 name을 추출한다.세터함수에 inputs(name,nickname)를 전개연산자를 통해 넣고, e.target의 name에 해당하는 객체의 value에 업데이트 한다.자바스크립트의 객체배열에서 키는 중복이 불가능하지만 밸류는 중복되면 나중에 입력된 값으로 업데이트된다.
<- input의 입력값을 초기화한다.
useRef
JavaScript 를 사용 할 때, 특정 DOM을 선택해야 하는 상황이 오면 getElementById, querySelector 같은 DOM Selector 함수를 사용하여 DOM을 선택한다.
리액트를 사용하는 프로젝트에서도 가끔 DOM을 직접 선택해야 하는 상황이 발생하는데, 이때 리액트에서 ref라는 것을 사용한다.
함수형 컴포넌트에서 ref를 사용 할 때에는 useRef라는 Hook함수를 사용한다.
클래스형 컴포넌트에서는 콜백함수를 사용하거나 React.createRef 라는 함수를 사용하는데, Hook함수가 추가됨에 따라 클래스형 컴포넌트보다 함수형 컴포넌트를 주로 사용하게 되었다.
위의 예제에서 초기화 버튼을 누르면 포커스는 초기화 버튼에 남아있게 된다.
이를 초기화 버튼을 눌렀을 때 포커스가 input에 잡히도록 하려면 useRef를 사용하여 기능을 구현한다.

<- useRef 함수를 불러온다.
<- Ref 객체를 만든다.
<- corrent는 원하는 DOM을 가르킨다.
초기화버튼을 클릭하는 이벤트가 발생했을 때,
corrent는 input 에 포커스를 하는 focus() DOM API 를 호출한다.
<- Dom을 선택할 수 있도록 위치를 지정한다.
단 4줄을 추가해서 포커스 기능을 추가했다.
배열 렌더링

이러한 배열을 가진 컴포넌트를 만든다면 기본적인 방법은 비효율적이지만 그냥 그대로 작성하는 것이다.

하지만 이러한 방식은 재사용이 힘들고, 배열이 많아지면 관리하기가 까다롭다.


배열은 그대로 유지하되, 코드를 재사용하는 컴포넌트를 선언하여 User의 name과 email을 불러들인다.
또한 기존 컴포넌트의 배열 접근방식을 새 User 컴포넌트를 불러오는 형식으로 변경한다.
하지만 이러한 형식은 동적인 배열을 렌더링 할 수 없다.
이때 자바스크립트 배열의 내장함수 map()을 사용한다.
map() 함수는 배열안에 있는 각 원소를 변환하여 새로운 배열을 생성한다.

이렇게 하면 배열의 모든 원소가 렌더링된다. 하지만 콘솔에서는 에러가 발생하는데,
리액트에서는 배열을 렌더링 할 때 key라는 props를 설정해야 한다.
key값으로는 원소들마다 가지고 있는 고유값으로 설정을 해야한다.
이 코드의 경우 각 원소의 id가 그 역할을 할 수 있다.

만약 key 설정으로 사용할 고유값이 존재하지 않는다면 배열의 index가 그 역할을 한다.
key 의 존재유무에 따른 업데이트 방식 차이

이러한 배열이 존재 할 때, map을 이용하여 'b'와 'c'사이에 'z'를 삽입하는 렌더링을 진행하는데, key값이 없다면 렌더링 과정에서 한칸씩 밀려나며 대입된다. b와 c 사이에 z가 삽입되는 것이 아닌 c가 z가 되고 d가 c가 되고 d가 마지막에 추가되는 형식으로 삽입된다.
이러한 비효율적인 과정을 가지지만, key가 있다면 원하는 위치에 원하는 원소를 삽입하고 제거할 수 있다.
따라서 배열을 렌더링 할 때에는 고유한 key 값이 있는것이 중요며 배열안에 중복되는 key가 있을 때는 렌더링 시에 업데이트가 제대로 이루어지지 않는다.
useRef 로 컴포넌트 안의 변수 만들기
컴포넌트에서 특정 DOM을 선택할 때 함수형 컴포넌트에서는 useRef를 사용한다.
useRef는 DOM선택하는 용도 외에 다른 한가지 용도가 더 있다.
그것은 컴포넌트 안에서 조회 및 수정을 할 수 있는 변수를 관리하는 것이다.
useRef로 관리하는 변수는 값이 바뀐하고 해서 컴포넌트가 리렌더링되지 않는다.
리액트 컴포넌트에서는 상태를 바꾸는 함수를 호출하고 나서 렌더링되면 업데이트된 상태를 조회 할 수 있는 반면에 useRef로 관리하는 변수는 설정 후 바로 조회할 수 있다.
이 변수를 사용하여 다음과 같은 값을 관리 할 수 있다.
* setTimeout, setInterval을 통해서 만들어진 id
* 외부 라이브러리를 사용하여 생성된 인스턴스
* scroll의 위치
위에서 작성한 UserList를 useRef를 이용하여 변경한다.
먼저 users 배열을 App.js로 이동한다.

배열 뒤에 nextId라는 변수와 추후 배열에 항목 추가하기를 진행할 onCreate 이벤트의 틀을 잡아둔다.

useRef()를 사용 할 때 파라미터를 넣어주면 이 값이 .current의 기본값이 된다.
배열에 항목 추가하기
input 두 개와 button 하나로 이루어진 CreateUser.js 컴포넌트를 새로 만든다.

이 컴포넌트의 상태관리는 CreateUser에서 하지 않고 App.js에서 진행하며, input의 밸류 및 이벤트로 등록할 함수들을 props로 전달받아서 사용한다.
관련 밸류 및 이벤트를 App.js에 추가한다.

<- import 구문이 추가되었다.
<- useState를 추가한다.
<- 비구조화 할당을 통해 값을 추출한다.
<- onChange 이벤트가 발생 할 때 input의 name이 같은 객체에 value를 업데이트한다.

<- 다음 추가될 user의 id
<- user를 추가한다.
<- 새롭게 생성한 배열을 기존 배열의 뒤에 추가한다.
<- 세터함수를 호출하여 초기화한다.
<- 배열을 추가한 후 다음 추가될 id를 1 증가시킨다.
<- CreateUser.js 에 전달할 props들
배열에 변화를 줄 때에는 객체와 마찬가지로 불변성을 지켜야 한다.
그렇게 때문에 배열의 push, splice, sort등의 함수는 사용하면 안된다.
그럼에도 만약에 사용해야 한다면 기존의 배열을 복사하고 나서 사용해야 한다.
불변성을 지키면서 배열에 새 항목을 추가하는 방법은 두 가지가 있다.
첫 번째는 spread연산자(전개 연산자)를 사용한다.
위의 예제들은 spread연산자를 사용하여 작성하였다.
두 번째는 concat() 함수를 사용하는 것이다. concat 함수는 기존의 배열을 수정하지 않고, 새로운 원소가 추가된 새로운 배열을 만든다.


이런식으로 변경된다.
불변성
리액트는 상태값을 업데이트 할 때 얕은 비교를 수행한다.
즉 배열이나 객체의 속성 하나하나를 비교하는게 아니라 이전 참조값과 현재 참조값만을 비교하여 상태 변화를 감지하는 것이다.
이런 이유로 배열이나 객체를 업데이트 할때 새로운 참조값을 가진 배열이나 객체를 생성하는 것이다.
불변성을 지킴으로써 리액트는 상태변화를 감지할 수 있다.
또한, 불변성을 지켜줌으로써 얻게 되는 또 다른 이점은 바로 사이드 이펙트를 방지하는 것이다.
즉 외부에 존재하는 원본데이터를 직접 수정하지 않고, 원본데이터의 복사본을 만들어서 값을 사용하기에 예상치 못한 오류를 사전에 방지할 수 있다.
내용 정리
props 는 properties 의 줄임말이다.
우리가 어떠한 값을 컴포넌트에게 전달해줘야 할 때, props 를 사용한다.
여러개의 props는 비구조화 할당으로 간결하게 작성한다.
defaultProps 로 기본값 설정가능하다.
컴포넌트 태그 사이에 넣은 값을 조회하고 싶을 땐, props.children을 사용한다.
javascript에서는 null,false,undefined를 렌더링 하면 아무것도 나타나지 않는다.
삼항연산자를 이용해 조건부 렌더링을 할 수 있다.
삼항연산자대신 &&을 사용하면 첫번째로 나오는 false값을 반환하며, false값이 없다면 마지막 값을 반환한다.
리액트에서 이벤트 설정을 주로 "on이벤트이름={함수이름}" 형태로 작성한다.
useState선언은 const [현재상태, 세터함수] = useState(기본값); 으로 선언한다.
리턴문에 함수 호출문을 입력 시 렌더링되는 시점에 함수가 호출되기 때문에 함수를 저장한 변수를 호출한다.
input의 onChange를 사용하면 이벤트 객체 e의 값을 파라미터로 받아올 수 있다.
이 객체의 e.target은 이벤트가 발생한 DOM을 가리킨다.
e.target.value를 조회하면 현재 input의 value값을 알 수 있다.
input의 상태를 관리하기 위해서는 input 태그의 value값도 설정한다.
onChange는 input의 상태가 변할때마다 실행된다.
주로 input 태그의 이벤트값을 받아와서 name과 value를 비구조화 할당을 통해 추출한다.
비구조화 할당 : 객체를 추출하는 방법
구조분해 할당 : 객체나 배열을 변수로 '분해’할 수 있게 해주는 특별한 문법
javascript에서 특정 Dom을 선택하는 역할은 getElementById, querySelector이 하고, 리액트에서는 useRef가 한다.
특정 DOM에 접근할 때 사용한다.
외부 라이브러리 사용할때 유용하다.
원하는 위치에 ref={} 의 형태로 작성하면 된다.
포커스를 잡으려면 nameInput.current.focus() 형태로 작성하면 된다.
불변성은 변하지 않는 성질이다.
리액트는 상태를 업데이트 할 때 얕은 비교를 통해 업데이트를 한다.
데이터 하나하나 살펴보는 것이 아닌, 객체의 메모리주소를 보고 이전 참조값과 현재 참조값이 같은지만 비교한다.
이런 이유로 리액트는 새로운 참조값을 가진 새로운 객체를 생성한다.
또한 원본을 수정하는 것이 아닌, 복사본을 생성하여 수정함으로 예상치 못한 오류를 사전에 방지한다.'AI 솔루션 개발자과정(Java, Python)' 카테고리의 다른 글
36일차 - 장고 + 부트스트랩 파이썬 웹 개발 (1) 2022.11.28 35일차 - 리액트 입문 (2)... 리액트 마무리(다음차수부터 백엔드) (0) 2022.11.25 33일차 - node.js(2) 그리고 리액트(JSX 규칙) (0) 2022.11.23 32일차 - node.js (0) 2022.11.22 31일차 - 자바 스크립트 기본 문법(4) (0) 2022.11.21