React : 컴포넌트와 Props, State (+ useState 훅)
컴포넌트란?
- 스스로 상태를 관리하는 캡슐화된 코드 조각
=> 화면을 각 요소로 쪼갠 것
- 하나의 JSX 를 반환하는 함수
컴포넌트 만들기
- PascalCase를 사용하여 컴포넌트를 만든다.
- 컴포넌트는 기본적으로 함수이기 때문에 자신만의 고유한 로직이 들어갈 수 있다.
함수 형태로 컴포넌트를 만들게 되면 함수 스코프에 의해서 외부와 내부 스코프가 나눠지기 때문에
- 스스로 상태(state)를 가질 수 있다.
- 컴포넌트는 명확한 범위와 의미를 가질 수 있도록 파일을 분리한다
=> 각각 개별의 파일로 나눈다.
- 최상위 컴포넌트의 이름은 암묵적으로 App이다.
=> 루트 컴포넌트
- 최상위 컴포넌트(App)을 렌더링 하는 코드는 index.js에 둔다.
=> 엔트리 포인트
Props
부모 컴포넌트에서 자식 컴포넌트로 내려주는 데이터
function App() { // 상위 컴포넌트
return <One name={'lala'} />;
}
function One(props) { // 하위 컴포넌트
return <h1>{`hi ${props.name}`}</h1>; // hi lala
}
Props의 특징
- 구조분해할당 구문을 활용해서 props를 전달할 수 있다.
function App() {
return <One name={'lala'} />;
}
function One({ name }) { // props에서 -> {name} 으로 구조분해 할당을 해서 적용
return <h1>{`hi ${name}`}</h1>; // hi lala // -> props.name 에서 name 으로 적용
}
- 특정 Props에 초기 값을 지정할 수 있다.
function App() {
return <One />;
}
function One({ name = 'koko' }) {
return <h1>{`hi ${name}`}</h1>; // hi koko
}
- Props는 읽기 전용이다. (하위 컴포넌트에서 props를 수정할 수 없다)
상위 컴포넌트에서 하위 컴포넌트로 값(컴포넌트 도 가능)을 보내는 방법
props.children 사용
function App() { // 상위 컴포넌트
return (
<One>
<li>hello</li>
<li>world</li>
</One>
);
}
function One(props) { // 하위 컴포넌트
return <ul>{props.children}</ul>;
}
위와 같이 props.children 으로 전달하면
<ul>
<li>hello</li>
<li>world</li>
</ul>
이런 코드가 된다.
응용하기
props로 type과 children을 함께 전달한다.
function App() {
return (
<div>
<One type={'h1'}>Hi!!</One>
<One type={'h2'}>Hello!</One>
</div>
);
}
function One(props) {
if (props.type === 'h1') {
return <h1>{`myType is ${props.type} ${props.children}`}</h1>;
} else {
return <h2>{`myType is ${props.type} ${props.children}`}</h2>;
}
}
State
컴포넌트 내부에서 사용되는 변수
- state 값이 변하면 컴포넌트가 리렌더링 된다.
- 렌더링 사이클에서 값이 보존된다.
State 가 필요한 이유
export default function Count() {
let value = 0;
return (
<>
<h1>value : {value}</h1>
<button
onClick={() => {
value += 1;
console.log(value);
}}
>
증가
</button>
<button
onClick={() => {
value -= 1;
console.log(value);
}}
>
감소
</button>
</>
);
}
버튼을 클릭했을 때 value가 증가하지 않는다
콘솔에는 이상 없이 value가 증가, 감소 하고 있다.
=> value의 변수가 변하더라도 컴포넌트가 실행되는 것(렌더링) 되는 것이 아무런 관련이 없어서 변하지 않는 것이다.
그래서 컴포넌트를 리렌더링 할 수 있는 State가 필요하다.
useState
- useState 인자 값 : 초기 값
- useState 라는 훅은 배열을 반환한다.
배열에 들어가는 요소 => [state 자체의 값(변수), 앞의 state를 변환시키는 setter 함수]
ex) [state, setState] = useState(초기 값)
setter 함수를 통해서 state 값을 변경하면 컴포넌트가 state 값이 변경되었구나를 알 수 있다
setter를 통해서 state가 변경되면 화면을 다시 그려주는 동작을 한다.
const [value, setValue] = useState(0); // value : state 값 // setValue : value를 변경시키는 setter 함수 // (0) : 초기 설정 값
위 코드를 아래와 같이 수정할 수 있다.
import React, { useState } from 'react';
export default function Count() {
const [value, setValue] = useState(0); // state로 value를 관리, 초기 값은 0
return (
<>
<h1>value : {value}</h1>
<button
onClick={() => {
setValue(value + 1);
}}
>
증가
</button>
<button
onClick={() => {
setValue(value - 1);
}}
>
감소
</button>
</>
);
}
‼️setState해서 state 를 바로 변경하는 것이 아니라, 해당 컴포넌트의 모든 렌더링이 끝난 후 (로직 실행이 모두 끝난 후) 한꺼번에 모아서 setState를 해준다.