
리액트: 사용자 인터페이스를 만들기 위한 대표적인 자바스크립트 UI 라이브러리 (화면을 만들기 위한 기능들을 모아놓은 것)
라이브러리: 자주 사용되는 기능들을 정리해서 모아놓은것 → 흐름을 제어하지 않고 개발자가 필요한 부분만 가져다 쓰는 것
사용자 인터페이스(UI): 서로간의 입력과 출력 제어
Virtual Dom: 웹사이트의 모든 정보를 담음. 웹페이지를 정의하는 하나의 객체, 가상의 Dom으로 웹페이지와 실제 dom 사이의 매개체 역할을 함 (빠른 렌더링, 변경된 부분만을 다시 렌더링)
컴포넌트 기반의 구조→ 리액트로 구성된 페이지는 모두 컴포넌트로 이루어져 있음. 이는 재사용성을 높임 → 개발기간 단축, 유지보수 용이
리액트로 개발할 때 컴포넌트의 영역들을 잘 분리하여 재사용성이 높은 컴포넌트를 만드는 것이 중요
create-react-app(CRA) 리액트로 개발을 할 때 필요한 모든 환경설정이 되어있음
개발환경 설정시 필요한 환경 (Node.js설치, Npm설치, vscode)
npx(execute npm package binaries) Npm 패키지를 설치한 이후 곧바로 실행할 수 있도록 해 주는 명령어
vscode 터미널에서 실행할 수 있음
npx create-react-app my-app //project name
cd my-app //경로 변경(디렉토리 변경) 생성한 mt-app폴더로 이동
npm start //애플리케이션 실행
명령어 입력후 로컬 개발환경에서 리액트 애플리케이션이 실행 됨
A syntax estension to JavaScript 자바스크립트의 확장 문법
자바스크립트의 문법을 확장시킨 것 JavaScript + XML/HTML
const element = <h1>Hello, world!</h1>;
h1 태그로 둘러싸인 문자열을 element라는 변수에 저장
JSX의 역할
JSX는 내부적으로 xml, html코드를 자바스크립트로 변환하는 과정을 거침
Jsx로 코드를 작성해도, 최종적으로는 자바스크립트 코드로 나오는 것
Jsx문법을 사용하면 리액트에서는 내부적으로 createElement함수를 사용하도록 변환
동일한 코드

React.createElement()의 결과로 아래와 같은 객체 생성

JSX의 장점
JSX사용법
XML, HTML 코드를 섞어 사용하다 JS를 사용하고 싶을 경우 {}중괄호를 사용하여 변수나 함수 사용
element 리액트 앱을 구성하는 가장 작은 블록들
React Element는 Dom Element의 가상표현, 여기서 말하는 element는 react element임
리액트 Elements는 실제로 화면에서 보이는 것들을 기술
불변성: 한번 생성된 element는 변하지 않음 → 생성 후에는 children이나 attributes를 바꿀 수 없음
컴포넌트와 엘리먼트의 관계

화면에 변경된 element들을 보여주는 방법?
기존 element를 변경하는 것이 아니라 새로운 element를 만들어 기존과 바꿔치기 하면 됨
밑의 원 하나하나는 모두 element, 빨간색 원은 변경된 element라고 보면 됨

화면이 새로 갱신될 때, 새로운 element로 바꿔치기 된다
생성한 elements를 실제 화면에 보여주기 위해서는 렌더링의 과정 필요
//Root DOM Node
<div id="root"></div>
div 태그 안의 리액트 elements들이 렌더링되며 이들은 React DOM에 의해서 관리됨
오직 리액트만으로 만들어진 웹사이트들은 단 하나의 Root DOM Node를 가짐
위의 트리 그림에서 가장 최상단에 있는 것이 Root DOM Node
리액트는 컴포넌트 기반의 구조를 지님, 여러개의 컴포넌트의 조합으로 이루어짐
→ 레고 블록 조립하듯 컴포넌트들을 모아 개발
→ 컴포넌트들을 반복적으로 사용하며 하나의 페이지 개발
→ 컴포넌트를 반복적으로 사용하며 개발시간과 유지보수비용 단축
작은 컴포넌트들이 하나의 컴포넌트를 이루고, 각 컴포넌트들이 전체 페이지를 구성

리액트의 컴포넌트는 입력이 있으면 출력이 있음. 따라서 그냥 하나의 함수라고 생각하면 편함
BUT 리액트 컴포넌트는 일반적인 자바스크립트 함수와는 다름

Props는 Prop(react component의 속성)이 여러개인것을 의미
컴포넌트에 전달할 다양한 정보를 담고 있는 자바스크립트 객체
ex) 붕어빵에 들어가는 재료(props)가 다르면 다른 붕어빵이 만들어지는 것과 같음
같은 리액트 컴포넌트에서 눈에 보이는 글자나 색깔 등을 바꾸고 싶을 때 사용하는 컴포넌트 속 재료

4개의 여행지가 존재, 네 개의 카드는 모두 같은 모양이지만 배경이미지와 하단 부분의 색상이미지는 모두 다름
→ 모두 같은 컴포넌트에서 생성된 elements
→ 컴포넌트의 모습과 속성을 결정하는 것이 props

→ 컴포넌트에 어떤 데이터를 전달하고 전달된 데이터에 따라 다른 모습의 element를 화면에 렌더링하고 싶을 때, 해당 데이터를 props에 넣어서 전달
다른 Props로 element를 생성하려면?
모든 리액트 컴포넌트는 그들의 Props에 관해서 Pure 함수 같은 역할을 해야 한다
→ 모든 리액트 컴포넌트는 Props를 직접 바꿀 수 없고, 같은 Props에 대해서 항상 같은 결과를 보여줘야 한다.
→ 리액트 컴포넌트의 입력으로 들어오는 Props는 자바스크립트 함수의 파라미터와 같다
인터넷 서치~후 실습
함수형 컴포넌트와 클래스형 컴포넌트가 있지만 최근에는 함수형 컴포넌트 사용 추세

함수형 컴포넌트
function Welcome(props){
return <h1>안녕, {props.name}</h1>;
}
이 함수의 경우 하나의 Props객체를 받아서 인사말이 담긴 하나의 react element를 리턴, 간결한 코드
클래스형 컴포넌트 (위의 코드와 동일한 역할)
class Welcome extends React.Component {
render() {
return <h1>안녕, {this.props.name}</h1>;
}
}
함수형 컴포넌트와 가장 큰 차이점은 모든 클래스 컴포넌트는 React.Component를 상속받아서 만듦
React.Component를 상속받았기 때문에 결과적으로는 리액트 컴포넌트가 되는 것
항상 대문자로 시작해야 한다

컴포넌트는 붕어빵 틀의 역할을 하기 때문에, 렌더링시 component가 렌더링 되는 것이 아니라 컴포넌트라는 붕어빵 틀에 찍혀서 나온 element가 실제로 화면에 보이게 됨

리액트는 welcome 컴포넌트에 {name: “인제”}라는 props를 넘겨 호출하고, 그 결과로 react element생성
생성된 element는 DOM을 통해 업데이트되고, 우리는 브라우저를 통해 볼 수 있음
여러개의 컴포넌트를 합쳐 하나의 컴포넌트를 만드는 것
리액트는 컴포넌트 안에 또 다른 컴포넌트를 쓸 수 있기 때문에, 복잡한 화면을 여러개의 컴포넌트로 나눠서 구현 가능하다.
Props의 값을 다르게 하여 세 번의 Welcome 컴포넌트를 사용하고 있음
App 컴포넌트는 세 개의 welcome 컴포넌트를 포함


앱 컴포넌트를 루트로 하여 3개의 하위 컴포넌트로 구성
복잡한 컴포넌트를 쪼개서 여러개의 컴포넌트로 나누는 것
컴포넌트 추출을 잘 활용한다면 재사용성, 개발속도가 높아짐→ 컴포넌트가 작아질수록 해당 컴포넌트의 기능과 목적이 명확해지고 단순해지기 때문
컴포넌트 추출 과정

아바타 추출

추출된 아바타 컴포넌트의 모습

추출된 아바타 컴포넌트가 반영된 모습

UsrInfo 추출

아까 추출했던 아바타 컴포넌트도 함께 추출된 것을 볼 수 있음

유저인포 컴포넌트를 반영했을 경우 코드→ 코드가 단순해지고 가독성이 높아짐

지금까지 추출한 컴포넌트의 구조

컴포넌트는 기능 단위로 구분하는 것이 좋고, 재사용이 가능한 형태로 추출 할 것
재사용 가능한 컴포넌트들을 많이 갖고 있을 수록 개발 속도가 빨라진다!
리액트의 state = 리액트 Component의 상태, 리액트 컴포넌트의 변경 가능한 데이터
State는 사전에 정의된 것이 아니라 개발자가 정의해서 사용하게 됨

this.state → 현재 컴포넌트의 state를 정의하는 부분
state는 정의된 이후 직접 수정할 수 없다(직접적인 수정 불가) → 컴포넌트 렌더링과 관련되어있기 때문에, 개발자가 직접 수정하게 되면 의도한대로 작동하지 않을 수 있음

state를 변경하기 원할때는 꼭 setState함수를 사용해서 변경해야 함
컴포넌트는 계속 존재하는 것이 아니라 시간의 흐름에 따라 생성되고, 업데이트 되다 사라진다


훅을 사용하면 함수 컴포넌트도 클래스 컴포넌트 기능을 모두 동일하게 구현 가능

리액트의 state와 생명주기에 갈고리를 걸어 원하는 시점에 정해진 함수를 실행되도록 만들고, 이때 실행되는 함수를 훅이라고 함
훅은 이름 앞에 use를 사용한다는 규칙을 가짐
state를 사용하기 위한 훅
//사용법
const [변수명, set함수명] = useState(초기값);
예시 코드는 useState를 사용하여 카운트 값을 state로 관리하도록 한 것
버튼이 눌렸을 때, setCount함수를 호출하여 count를 1 증가시킴
카운트값이 변동되면 컴포넌트가 재렌더링 되면서 새로운 카운트 값 표시됨

리액트의 함수 컴포넌트에서 Side effect(서버에서 데이터를 받아오거나, 수동으로 dom을 변경하는 작업 등)를 수행하기 위한 훅
//사용법
useEffect(이펙트 함수, 의존성 배열);
//Effect function이 mount,unmount 시에 단 한번씩만 실행되게 하고싶을 경우
useEffect(이펙트 함수, []);
//의존성 배열을 생략하면 컴포넌트가 업데이트 될 때마다 호출됨
useEffect(이펙트 함수);
의존성 배열: 이 이펙트가 의존하고 있는 배열인데, 배열 안에 있는 변수중에 값이 하나라도 변경되었을 때 이펙트 함수가 실행됨

Effect는 함수 컴포넌트 안에서 선언되어서 해당 컴포넌트의 state와 props에 접근할 수 있음
Memoization 최적화를 위해 사용하는 개념. 연산량이 많이 드는 함수의 호출 결과를 저장해두었다가, 같은 입력값으로 함수를 호출하면, 새로 함수를 호출하지 않고 이전에 저장에 두었던 결과를 반환하는 것 (메모해 두었다가 나중에 다시 사용하는 것과 같은 개념)
useMemo()사용법

useMemo() hook과 유사하지만 값이 아닌 함수를 반환
컴포넌트가 렌더링 될 때마다 매번 함수를 새로 정의하는 것이 아니라, 의존성 배열의 값이 바뀐 경우에만 함수를 새로 정의하여 리턴
useCallback()사용법

//동일한 역할을 하는 두 줄의 코드
useCallback(함수, 의존성 배열);
useMemo(()=> 함수, 의존성 배열);
레퍼런스(특정 컴포넌트에 접근할 수 있는 객체)를 사용하기 위한 Hook
//사용법
const refContainer = useRef(초기값);
1) Hook은 무조건 최상위 레벨(리액트 함수 컴포넌트의 최상위 레밸)에서만 호출해야 한다
→ 반복문이나 조건문, 또는 중첩된 함수에서 호출 불가
→ Hook은 컴포넌트가 렌더링될 때마다 매번 같은 순서로 호출되어야 한다
2) Hook은 리액트 함수 컴포넌트에서만 호출해야 한다
→ 일반적인 자바스크립트 함수에서 훅을 호출할 수 없음
이름이 use로 시작하고 내부에서 다른 Hook을 호출하는 하나의 자바스크립트 함수

밑) 위의 두 개의 컴포넌트에서 중복되는 로직을 추출해서 가져온 것

커스텀 훅은 특별한 규칙이 없고, 파라미터로 무엇을 받을지 무엇을 리턴할지를 개발자가 직접 정할 수 있음

커스텀 훅 적용 예시. 커스텀 훅의 이름은 꼭 use로 시작해야 한다!
여러개의 컴포넌트에서 하나의 커스텀 훅을 사용할 때, 컴포넌트 내부에 있는 모든 state와 effects는 전부 분리되어 있다.
리액트는 각 커스텀 훅 호출에 대해서 분리된 state를 얻게 됨
각 커스텀 훅의 호출 또한 완전히 독립적
리액트의 event는 괄호 안에 함수를 그대로 전달
<button onClick={activate}>
Activate
</button>
Dom과 리액트는 함수를 표기하는 방법에서 차이 존재

이벤트가 발생했을 때, 해당 이벤트를 처리하는 함수

arguments, Parameter : Event Handler에 전달할 데이터
매개변수를 event handler에 전달하는 방법
매개변수의 순서는 원하는대로 변경해도 상관 없음

각 객체나 아이템을 구분할 수 있는 고유한 값, 아이템들을 구분하기 위한 고유한 문자열
map함수를 사용하여 numbers배열에 들어있는 각 숫자에 2를 곱한 값이 들어간 doubled 배열 생성
→ 배열의 모든 아이템에 각 연산을 수행한 뒤, 그 결과를 배열로 만들어서 리턴
const doubled = numbers.map((number)=> number*2);
예시코드

최종적으로 렌더링된 결과

map() 함수 안에 있는 Elements는 꼭 key가 필요하다
key의 값은 같은 List에 있는 Elements 사이에서만 고유한 값이면 됨
→ 두 대학교 사이에서는 학번이 같아도 상관없는 것처럼!

key값 사용에는 여러 방법이 있지만, 고유한 Id로 사용하는 것이 좋다

고유한 id가 없을 경우 index(배열 내 현재 아이템의 index의미)를 사용할 수 있다

사용자로부터 입력을 받기 위해 사용
리액트의 form은 html의 form과 다르다
html형식의 form 경우, 자바스크립트를 통해 각각의 값에 접근하기 어렵다

사용자가 입력한 값에 접근하고 제어할 수 있도록 하는 Controlled Components를 알아보자
값이 리액트의 통제를 받는 Input Form Element
리액트에서 모든 값을 통제할 수 있음

함수형 컴포넌트에서는 setState()이 아니라 useState로 관리
위의 html form을 리액트의 controlled components로 작성한 코드
→ 사용자의 입력을 직접적으로 제어할 수 있음

모든 입력값을 대문자로 변경하고 싶을 경우
const handleChange = (event) => {
setValue(event.target.value.toUpperCase());
}
textarea

select 태그 drop-down 목록을 보여줌
html방식

리액트 방식 (더 편리함)

여러개의 옵션 선택 가능
<select multiple={true} value={['b','c']}>
리액트에서는 모두 value라는 attribute를 통해 값을 전달하고, 값을 변경할 경우 onChange value 함수를
사용하여 값을 업데이트

file input 태그: 디바이스의 저장 장치로부터 하나 또는 여러개의 파일을 선택할 수 있게 해주는 html xorm
Html 방식, 리액트에서는 값이 리액트의 통제를 받지 않는 Uncontrolled Component가 됨
<input type="file"/>
Multiple Inputs 하나의 컴포넌트에서 여러개의 입력을 다룰 경우
→ 여러 개의 state를 선언하여 각각의 입력에 대해 사용
→ 각각의 set 함수를 사용하여 구현

→ State에 있는 데이터를 여러개의 하위 컴포넌트에서 공통적으로 사용하는 경우
개발하다보면, 하나의 데이터를 여러 컴포넌트에서 표현해야 하는 경우 생김.
이 경우, 각 컴포넌트의 state에서 데이터를 각각 보관하는 것이 아니라, 가장 가까운 공통된 부모 컴포넌트의 state를 공유해서 사용하는 것이 더 효율적.


이 경우 자식 컴포넌트들이 각각 값을 가지고 있을 필요 없음
컴포넌트에서 데이터를 기존의 props를 통해 전달하는 대신, 컴포넌트 트리를 통해 곧바로 컴포넌트로 전달하는 방식을 제공 → 어떤 컴포넌트든지 데이터에 쉽게 접근할 수 있음

단점: 여러 컴포넌트에 걸쳐 자주 사용되는 데이터들은 반복적인 코드가 많이 생겨 지저분해짐, Props를 계속 하위 컴포넌트로 전달해야함
위의 단점을 해결하기 위해 context 사용.

코드도 깔끔해지고 데이터를 한 곳에서 관리하기 때문에 디버깅에 유리
언제 사용하면 좋을까?
로그인 여부, 로그인 정보, UI 테마, 현재 언어 등 ..

다른 방법~?

useContext() 훅도 있음 나중에 찾아볼 것
#npm 사용 경우
npm install --save styled-components
설치 후 간단한 실습 예시



다른 컴포넌트 부분의 스타일을 확장하고 싶을 경우
