해당 글은 2022/10/24 React Docs BETA 버전을 기반으로 작성되었습니다. 링크
React에서 props(properites)와 state는 일반 JavaScript 객체라고 한다.
두 객체는 모두 렌더링 결과물에 영향을 주는 정보는 갖고 있다.
props는 (함수의 매개변수처럼) 컴포넌트에 전달되는 반면에 state는 (함수 내에 선언된 변수처럼) 컴포넌트 안에서 관리된다.
state와 prop을 정리하면 아래와 같다.
- 둘 다 일반 자바스크립트 객체다
- state는 컴포넌트 안에서 사용된다
- props는 컴포넌트에 매개변수처럼 전달하는 것이다
State | Props | |
유스케이스 | 뷰에 렌더링돼야 하는 컴포넌트의 데이터를 저장하는 데 사용한다. | 데이터, 이벤트 핸들러를 자식 컴포넌트에 전달하는 데 사용한다. |
가변성 | 상태는 데이터를 보유하고 시간이 지남에 따라 변경될 수 있다. | props는 바뀔 수 없다. 한 번 설정되면 props를 변경할 수 없다. |
업데이트 | 이벤트 핸들러는 일반적으로 state를 업데이트한다. | 상위 컴포넌트는 하위 컴포넌트에 대한 props를 설정한다. |
State를 사용하는 이유
- State는 변경되면 자동으로 리렌더링 된다. (변수는 변경되어도 자동 리렌더링이 안됨)
state가 변경되어 리렌더링 하는 과정에서 Virtual DOM이 생성되는데 리액트에서 이전의 Virtual DOM과 다른 부분을 찾아내어 메모리에서 먼저 구현한 후 실제 DOM 부분만 업데이트한다.
상태의 객체 및 배열 업데이트 (Updating Objects and Arrays in state)
객체와 배열을 상태에 넣을 수 있다. React에서 상태는 읽기 전용으로 간주되므로 기존 객체를 변경 하는 대신 상태를 교체 해야한다. 상태는 읽기 전용이기에 불변성을 유지해야한다. 👉 불변성에 관한 내용
// 🚩 Don't mutate an object in state like this:
form.firstName = 'Taylor';
// ✅ Replace state with a new object
setForm({
...form,
firstName: 'Taylor'
});
상태의 객체에 직접 접근하여 바꾸는 것이 아니라 새 객체를 만들어 전체 객체를 바꾸어야 한다.
React에서 사용하는 상태는 읽기 전용이기에 새로운 객체를 만들어 필요한 부분만 업데이트 해야한다.
중첩된 객체나 배열이 존재하면 코드가 길어지기에 상태 관리를 위한 Redux, MobX, Immer와 같은 라이브러리를 사용할 수 있다.
초기 상태의 재생성 피하기( Avoiding recreating the initial state )
function TodoList() {
const [todos, setTodos] = useState(createInitialTodos());
// ...
createInitialTodos()함수는 초기 렌더링에만 사용되긴 하지만 모든 렌더링에서 이 함수를 호출한다. 이것은 연산의 낭비를 일으킬 수 있다. 이 문제를 해결하기 위해 초기화함수로 전달할 수 있다.
function TodoList() {
const [todos, setTodos] = useState(createInitialTodos);
// ...
함수 자체를 전달하는 것이지 createInitialTodos의 호출 결과(값)를 전달하지 않는다는 것에 주목해야한다.
useState에 함수 자체를 전달하면 React는 초기화하는 동안에만 호출한다. 초기화 함수 자체를 전달하지 않는 것은 비효율적인 코드가 된다.
React는 컴포넌트가 순수한지를 검증하기 위해 두번 호출할 수 있다.
이 말은 일부 JavaScript 함수는 순수하다. 순수 함수는 계산만 수행하고 그 이상은 수행하지 않기에. 구성 요소를 순수 함수로만 작성하면 코드베이스가 커짐에 따라 전체 클래스의 당황스러운 버그와 예측할 수 없는 동작을 피할 수 있다.
즉, 순수 함수로 작성되는 것이 좋고 그에 따른 검증 또한 이루어진다는 것이다. 👉 순수 함수
Key를 이용하여 상태 재설정하기
일반적으로 목록을 렌더링할 때 key 속성을 마주하게 된다.
컴포넌트의 키값을 달리하여 컴포넌트의 상태를 reset해줄 수 있다.
export default function AppKeyToReset() {
const [version, setVersion] = useState(0);
function handleReset() {
setVersion(version + 1);
}
return (
<>
<button onClick={handleReset}>Reset</button>
<Form key={version} />
</>
);
}
function Form() {
const [name, setName] = useState('Taylor');
return (
<>
<input
value={name}
onChange={e => setName(e.target.value)}
/>
<p>Hello, {name}.</p>
</>
);
}
정민을 입력하고 Reset버튼을 눌러보자.
version이 1증가하면서 Form 컴포넌트의 key값이 1증가하였다.
이때 Form의 상태인 name이 재설정되면서 초기값을 가지게 된다.
Funtional Component
import React, {useEffect, useState} from 'react'
export default function FunctionalComponent() {
const [date, setDate] = useState(new Date());
const tick = () => {
setDate(new Date());
}
useEffect(() => {
const interval = setInterval(() => tick(), 1000);
return () => {
clearInterval(interval);
}
}, []);
return (
<div>
<h1>Hello, world! It's Functional</h1>
<h2>It is {date.toLocaleTimeString()}.</h2>
</div>
);
}
componentDidMount에서 하는 동작을 useEffect에서 하였다. componentWillUnmount에서 하는 동작은 return으로 만들어주었다. ClassComponent에서 상태관리는 this.state를 이용하여 초기화 해주었고, tick에서 setState를 이용하여 업데이트 처리를 해주었다. FunctionalComponent에서는 useState를 set할때 바로 초기화 해주었고, setDate값으로 tick에서 업데이트 해 주었다. hook이 나오면서 함수형 컴포넌트에서도 상태를 관리해줄 수 있게 되었다.
Props는 순수함수이기 때문에 변경하면 안되지만 컴포넌트 안에서 스스로 변경하고 싶으면 State를 사용한다.Class Component는 State LifeCycle별로 메소드가 존재한다 그것들로 State를 관리한다. Functional component는 훅으로 관리한다.
State 업데이트는 비동기적일 수도 있습니다.
React는 성능을 위해 여러 setState() 호출을 단일 업데이트로 한꺼번에 처리할 수 있습니다.
비동기적이다 라는 의미는 순차적으로 동작하지 않을 수도 있다는 의미이다.
this.props와 this.state가 비동기적으로 업데이트될 수 있기 때문에 다음 state를 계산할 때 해당 값에 의존해서는 안 됩니다.
예를 들어, 다음 코드는 카운터 업데이트에 실패할 수 있습니다.
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
이를 수정하기 위해 객체보다는 함수를 인자로 사용하는 다른 형태의 setState()를 사용합니다. 그 함수는 이전 state를 첫 번째 인자로 받아들일 것이고, 업데이트가 적용된 시점의 props를 두 번째 인자로 받아들일 것입니다.
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
위에서는 화살표 함수를 사용했지만, 일반적인 함수에서도 정상적으로 작동합니다.
// Correct
this.setState(function(state, props) {
return {
counter: state.counter + props.increment
};
});
정리하자면 Functional Component로 Class Component와 같은 기능을 구현할 수 있고, 그 안에서 상태를 관리하고 상태를 변경할 수 있다.
'개발자의 공부 > React' 카테고리의 다른 글
[React]useEffect (0) | 2022.11.08 |
---|---|
[React]useReducer (0) | 2022.10.24 |
[React]Page Routing (0) | 2022.09.30 |
[React]성능 최적화와 성능 체크(업데이트) (1) | 2022.09.29 |
[React]Lifecycle (0) | 2022.09.24 |