State(상태)
컴포넌트를 사용하는 와중에 컴포넌트 내부에서 변할 수 있는 것
실생활에서 예시를 들어보면, 나이, 취업 여부, 현재 사는 곳, 결혼/연애 여부같이 변경이 가능한 부분들
토글 스위치 온 오프, 체크박스 체크가 되었는지 아닌지, input 텍스트에 글이 입력이 되었는지 여부 등등
React 에서는 이러한 state 를 다루는 방법 중의 하나로 useState 라는 특별한 함수를 제공한다.
useState 함수는 React Hook을 사용하기 위해 쓴다. 함수형 컴포넌트에 적용된다.
어느정도 차이점을 보이기 위해 Class Component 일때의 예시도 들어본다.
useState 사용 방법
먼저 useState 를 컴포넌트 안에서 호출한다. useState 를 호출한다는 것은 "state" 라는 변수를 선언하는 것과 같으며, 이 변수의 이름은 아무 이름으로 지어도 된다. 일반적으로 일반 변수는 함수가 끝날 때 사라지지만, state 변수는 React 에 의해 함수가 끝나도 사라지지 않는다.
function CheckboxExample() {
// 새로운 state 변수를 선언하고, 여기서는 이것을 isChecked로 정한다. (체크박스 예시)
const [isChecked, setIsChecked] = useState(false);
Class Component일 때의 예시를 들어보면,
useState 를 호출하면 배열을 반환하는데, 배열의 첫 번째 요소는 현재 state 변수(reduce를 예시로 들면, current 값) 이고, 두 번째 요소는 이 변수를 갱신할 수 있는 함수(reduce를 예시로 들면 acc 값)이고, useState 의 인자로 넘겨주는 값은 state 의 초기값이다.
function CheckboxExample() {
const [isChecked, setIsChecked] = useState(false);
// const [state 저장 변수, state 갱신 함수] = useState(state 초기 값);
// const [isChecked, setIsChecked] = useState(false);에서
// isChecked 와 setIsChecked 는 state 저장 변수와 state 갱신 함수를 의미한다.
// isChecked 라고 부르는 state 변수를 선언하고 useState() 에 이 변수를 아직 체크되지 않은 상태인 false 로 초기화한 상태
// React 는 이 변수를 리렌더링할 때 기억하고, 가장 최근에 갱신된 값을 제공한다.
// isChecked 변수의 값은 setIsChecked 함수를 호출하여 갱신할 수 있다.
function CheckboxExample() {
const [isChecked, setIsChecked] = useState(false);
const handleChecked = (event) => {
setIsChecked(event.target.checked);
};
return (
<div className="App">
<input type="checkbox" checked={isChecked} onChange={handleChecked} />
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>
</div>
);
}
// state 를 갱신하려면 변수를 갱신할 수 있는 함수인 setIsChecked 를 호출해야 한다.
// 다만, 이 함수를 직접 호출하는 것이 아닌, 사용자의 입력값을 처리하는 onChange 이벤트를 이용한다.
// 사용자가 입력을 하면 onChange 이벤트가 이벤트 핸들러 함수인 handleChecked 를 호출하고,
// 이 함수가 setIsChecked 를 호출하게 된다.
// setIsChecked 가 호출되면 호출된 결과에 따라 isChecked 변수가 갱신되며,
// React 는 새로운 isChecked 변수를 CheckboxExample 컴포넌트에 넘겨 해당 컴포넌트를 다시 렌더링 한다.
위의 예시와 비슷한 다른 예시로 useState 함수와 기존에 사용되던 setState 함수의 차이점을 설명해보면
class SimpleHabit extends Component {
state = {
count: 0,
};
// 기존 Class Componet 상에서 미리 state의 초기 값을 선언해줬고,
handleIncrement = () => {
this.setState({ count: this.state.count + 1 });
};
// 함수를 통해 업데이트 되는 state 값을 setState함수를 통해 업데이트 해주었다.
// 위의 초기 값을 사용하기 위해 this를 사용한 것이 포인트
render() {
return (
<li className="habit">
<span className="habit-name">Reading</span>
<span className="habit-count">{this.state.count}</span>
<button
className="habit-button habit-increase"
onClick={this.handleIncrement}
// 각 값을 업데이트 한 값을 웹페이지에 구현하기 위해 this를 계속 사용하는 모습을 볼 수 있다.
// 이러한 불편함을 해소하고자 React Hook이 도입되고, useState 함수를 통해 간결하게 코드를 작성하게 되었다.
>
<i className="fas fa-plus-square"></i>
</button>
</li>
);
}
}
const SimpleHabit = () => {
const [count, setCount] = useState(0)
const spanRef = useRef();
const handleIncrement = useCallback(() => {
setCount(count + 1 );
});
return (
<li className="habit">
<span ref = {spanRef} className="habit-name">Reading</span>
<span className="habit-count">{count}</span>
<button
className="habit-button habit-increase"
onClick={handleIncrement}
>
<i className="fas fa-plus-square"></i>
</button>
</li>
);
}
Props(속성)
외부에서 인자와 같이 받을 수 있는 값
실생활에서 예시를 들어보면, 이름, 성별, 고향처럼 변경이 어려운 부분들
컴포넌트의 속성(property)을 의미한다. 컴포넌트 내부에서 변하지 않는 외부로부터 전달받은 값으로, 웹 어플리케이션에서 해당 컴포넌트가 가진 속성에 해당한다.
상위 컴포넌트로부터 전달받은 값. React 컴포넌트는 JavaScript 함수와 클래스를 통해 만들어진 props를 함수의 전달인자(arguments)처럼 전달받아 이를 기반으로 화면에 어떻게 표시되는지를 기술하는 React 엘리먼트를 반환한다. 따라서, 컴포넌트가 최초 렌더링될 때에 화면에 출력하고자 하는 데이터를 담은 초기값으로 사용할 수 있다.
객체 형태이다. props로 어떤 타입의 값도 넣어 전달할 수 있도록 props는 객체의 형태로 전달된다.
props는 읽기 전용이다. props는 성별이나 이름처럼 외부로부터 전달받아 변하지 않는 값이어서 props는 함부로 변경될 수 없는 읽기 전용(read-only) 객체로 설정된다. 컴포넌트 내부에서 함부로 변경되지 않아야 하기 때문이다.
읽기 전용 객체가 아니라면 props를 전달 받은 하위 컴포넌트 내에서 props 를 직접 수정 시 props를 전달 한 상위 컴포넌트의 값에 영향을 미칠 수 있게 된다. 이는 React의 단방향, 하향식 데이터 흐름 원칙(React is all about one-way data flow down the component hierarchy)을 지키지 않는 것이며
개발자가 의도하지 않은 side effect가 생기게 되어 혼란을 초래하게 된다.
Props를 사용하는 방법 #1
- 하위 컴포넌트에 전달하고자 하는 값(data)과 속성을 정의한다.
- props를 이용하여 정의된 값과 속성을 전달한다.
- 전달받은 props를 렌더링한다.
위의 세 단계를 거치게 되는데, 예시를 들어 설명하기 위해 우선 <Parent> 와 <Child> 라는 컴포넌트를 선언하고, <Parent> 컴포넌트 안에 <Child> 컴포넌트를 작성한다.
function Parent() {
return (
<div className="parent">
<h1>I'm the parent</h1>
<Child />
</div>
);
};
function Child() {
return (
<div className="child"></div>
);
};
전달하고자 하는 속성을 정의한다. HTML에서 속성과 값을 할당하는 방법은 아래와 같은데,
<a href="www.codestates.com">Click me to visit Code States</a>
// tag 및 속성을 정하고, content를 작성한다.
React 에서 속성 및 값을 할당하는 방법도 이와 유사하다. 다만, 전달하고자 하는 값을 중괄호 {} 를 이용하여 감싸주면 된다.
<Child attribute={value} />
// <(props를 전달하고자 하는 컴포넌트 이름 = Child) (전달하고자하는 속성 = attribute)
// = {전달하고자 하는 값 = value} />
위 방법을 이용하여 Parent 컴포넌트에서 text 라는 속성을 선언하고, 이 속성에 "I'm the eldest child"라는 문자열 값을 할당하여 <Child> 컴포넌트에 전달하기 위해 코드를 작성하면, 아래와 같다.
function Parent() {
return (
<div className="parent">
<h1>I'm the parent</h1>
<Child text={"I'm the eldest child"} />
</div>
);
};
function Child() {
return (
<div className="child"></div>
);
};
<Parent> 컴포넌트에서 전달한 "I'm the eldest child"라는 문자열을 <Child> 컴포넌트에서 받는 방법은 간단한데, 함수에 인자를 전달하듯이 React 컴포넌트에 props 를 전달하면, Child Component에서 props 가 필요한 모든 데이터를 가지고 오게 된다.
function Child(props) {
return (
<div className="child"></div>
);
};
// Child 컴포넌트는 함수형 컴포넌트로 정리되어 있다.
// 함수의 매개변수로 props를 지정해줘도 되고, 아예 비워줘도 된다.
props 를 렌더링하려면 JSX 안에 직접 불러서 사용하면 된다. 다만, props 는 객체라고 하였고, 이 객체의 { key : value } 는 <Parent> 컴포넌트에서 정의한 { attribute : value } 의 형태를 띄게 됩니다. 따라서 JavaScript 에서 객체의 value 에 접근할 때 dot notation 을 사용하는 것과 동일하게 props 의 value 또한 dot notation 으로 접근할 수 있다. 아래와 같이 props.text를 JSX에 중괄호와 함께 작성하면 잘 작동된다.
function Child(props) {
return (
<div className="child">
<p>{props.text}</p>
</div>
);
};
Props를 사용하는 방법 #2
props.children
여는 태그와 닫은 태그의 사이에 value 를 넣어 props를 전달할 수 는데, 이 경우 props.children 을 이용하면 해당 value 에 접근하여 사용할 수 있다.
function Parent() {
return (
<div className="parent">
<h1>I'm the parent</h1>
<Child>I'm the eldest child</Child>
</div>
);
};
function Child(props) {
return (
<div className="child">
<p>{props.children}</p>
</div>
);
};
범용적인 ‘박스’ 역할을 하는 Sidebar 혹은 Dialog와 같은 컴포넌트에서처럼 어떤 자식 엘리먼트가 들어올 지 미리 예상할 수 없는 경우,
이러한 컴포넌트에서는 위의 방법인 children prop을 사용하여 자식 엘리먼트를 출력에 그대로 전달하는 것이 좋다.
https://ko.reactjs.org/docs/composition-vs-inheritance.html
합성 (Composition) vs 상속 (Inheritance) – React
A JavaScript library for building user interfaces
ko.reactjs.org
'개발 R.I.P.' 카테고리의 다른 글
6.11 Dev.Feedback(Math.sqrt 없이 제곱근 구하기 중 이해가 안되는 부분에 대해 정리 console.log 찍는 법 테스트) (0) | 2021.06.11 |
---|---|
6.11 Dev.Feedback(HA가 끝나고 새로운 MINDSET) (0) | 2021.06.11 |
6.08 Dev.Feedback (React #2 SPA, Router) (0) | 2021.06.08 |
6.07 Dev.Feedback(Array filter, map, reduce) (0) | 2021.06.07 |
6.06 Dev.Feedback ( 일급 객체, 고차 함수 개념) (0) | 2021.06.06 |