이게 왜 궁금해?
data.index.status === Status.Approval
or
const isAppoval = data.index.status === Status.Approval;
이라는 조건을 여러 곳에서 반복적으로 사용하게 되었다.
딱 봐도 길고, 반복적으로 사용하고, 여러 조건들과 함께 쓰일 경우에는 더 의미를 직관적으로 알 수 없었다.
그래서 isApproval
이라는 무언가
로 만들어 쓰려고 하는데 data가 변경될 때마다 isApproval 상태도 변경되어야 했다.
그래서 그냥 변수(variable)로 선언해도 될지, setState는 사용하지 않지만, state로 선언해야할지 궁금해서 찾아보았다.
결론부터
class variable은 변경했을 때 React가 알아채지 못한다.
state는 setState로 변경했을 때 react가 변화를 감지해 re-rendering된다.
내 코드의 경우 isApproval을 내가 직접 변경하지 않고, data에 따라 변하기 때문에 변화를 감지해 리렌더링 시켜야할 일은 없다. data가 변경되었을 때 렌더링되면서 isApproval의 값도 바뀌므로 변수로 사용해도 됨!
🤷♀️State가 뭐지?
// class variable
export default class Test extends Component {
render(props) {
super(props);
const isMe = this.props.name === 'Gisele';
return (
<div>
{isMe ? '나다' : '나 아니다'}
</div>
);
}
}
// state
export default class Test extends Component {
constructor(props) {
super(props)
this.state = { isMe : false };
}
render() {
if(this.props.name === 'Gisele') {
this.setState({isMe: true});
}
return (
<div>
{isMe ? '나다' : '나 아니다'}
</div>
);
}
}
state와 variable의 차이는 class형 컴포넌트에서 더 알기 쉬워서 가져옴.
State
는 컴포넌트의 현재 상황에 대한 정보를 나타내는 일반 자바스크립트 객체다(클래스형 컴포넌트에서). 일반 변수는 함수가 종료될 때 사라지지만, state는 값이 보존된다.
컴포넌트의 역할은 raw data를 HTML로 변환하는 것이기 때문에 이 raw data는 props와 state 객체로 구성되어 있다고 생각할 수 있다. props와 state가 render() 함수의 입력 데이터라고 할 수도 있다. 따라서 state는 구성 요소의 동작을 제어하는 일부 속성을 나타낸다.
state는 상태 변수에 변경 사항을 직접 적용하지 않는다. 이는 React에서 변경사항으로 간주되지 않기 때문이다. 대신 state의 상태는 setState()
를 사용해 변경한다. 그리고 setState는 비동기식이다. 한 줄에서 setState를 호출하고 다음 줄에서 상태가 업데이트가 된다는 보장은 없다. setState가 상태를 업데이트하라는 명령이 아니고 상태 업데이트에 대한 요청이기 때문이다. 이 문제를 해결하지 위해 업데이트가 적용된 후 실행되도록 보장되는 setState() 콜백 함수를 사용할 수 있다.
함수형 컴포넌트에서는 useState() 훅을 사용해 state를 관리한다. 클래스형 컴포넌트에서 state는 항상 객체지만, 함수형 컴포넌트에서는 모든 type이 state가 될 수 있다. 각 상태는 단일 값을 보유한다.
초기 값은 초기 렌더링에만 할당된다. 이후 렌더링에서 useState의 인수는 무시되고 현재 값이 검색된 값이 된다.
const Avartar = (user) => {
const [userState, setUserState] = useState(user);
// 해결
useEffect(()=>{
setUserState(user)
},[user])
return user.avartar && (<img src={user.avartar}>)
}
useState만 사용하면 해당 인수가 prop이 변경될 때마다가 아니라 처음에만 사용되기 때문에 작동하지 않는다. 이 문제를 해결하려면 들어오는 객체를 state로 사용할 때는 새 객체를 만들어야 한다.
그렇지 않으면 리액트는 객체의 변경을 감지하지 못한다.(객체는 참조형 data이기 때문에 객체 내부 값이 변해도 객체 자체의 주소값이 변하기 않기 때문)
const Message = ()=>{
const [messageObj,setMessageObj] = useState({message:''})
return (
<>
<input type='text'
value={messageObj.message}
onChange={e=>{
// 동작하지 않는 예시
messageObj.message = {e.target.value};
setMessage(messageObj)
// 동작하려면 새로운 객체를 만들어야 한다.
const new = {message:e.target.value};
setMessage(newMessageObj)
// 또는 setState의 첫 번째 인수인 prevState와 스프레드를 이용할 수 있다
setMessage(prevState=>{
return {...prevState,message:e.target.value}
})
}} />
</>
)
}
위 내용으로 state의 특징을 정리하면 다음과 같다.
- state는 컴포넌트의 어떤 정보를 갖고 있는 데이터다.
- state가 변경되면 React는 이를 감지해 render가 일어난다.
- state는 바로 할당하는 방식으로 변경하면 react가 변화를 감지하지 못하므로 setState를 이용해 변경한다.
- setState는 비동기로 처리되므로, setState 바로 다음 명령에서 새로운 값이 반영되지 않을 수 있음
- state를 객체로 사용할 경우 값을 할당할 때 스프레드 연산자 등을 이용해 새 객체를 만들어줘야함(객체의 data type이 참조형이기 때문에 내부값이 변해도 객체 자체의 주소값이 변하지 않기때문)
- setState는 첫 번째 인자로 이전 상태값을 갖는다.
그리고 내가 예전에 몰랐거나 실수를 범했던 것들의 이유를 알 수 있었다.
❓ 이 함수에서 setState를 여러번하면 렌더링이 매번 일어나나? -> 아니다. 해당 블럭이 모두 실행된 후! 렌더링이 일어난다.
❓ 객체 state가 왜 안바뀌었지? 새로운 객체를 생성하지 않고, 객체에 값을 바로 할당했기 때문
❓ 바로 위에서 setState를 했는데 왜 이전 상태값으로 처리가 됐지? 같은 함수 블럭 안에서 setState한 직후 실행한 것은 아직 state에 새로운 값이 반영되기 전이므로 그렇다. 코드 블럭이 다 실행된 후 state에 값이 반영된다.
State의 불변성
referece
'React' 카테고리의 다른 글
나만의 React 라이브러리 만들기 (0) | 2022.01.18 |
---|---|
presentational + container 패턴 (0) | 2021.10.30 |
React Query (0) | 2021.07.09 |