📖 state(상태)
변화하는 데이터.
애플리케이션을 렌더(render)하는데 있어 영향을 미칠 수 있는 값이다.
UI에 동적으로 표현되는 데이터, 즉 사용자의 액션에 따라서 변경될 수 있는 컴포넌트의 부분을 나타낼 수 있는 자바스크립트의 객체이다.
🔖 state 변경하기
함수 컴포넌트 내부에서 상태 관리 해야하는 일이 필요하다.
이를 위해서는 리엑트에서 제공하는 useState()를 사용한다.
setState()는 컴포넌트에 re-rendering을 발생시킨다.
import React, { useState } from "react"
const [state, setState] = useState(0)
버튼을 클릭하면 화면에 +1 한 값이 렌더링 된다.
🔖 불변성
프로그래밍에서 불변성을 지킨다
→ 메모리 영역의 값을 직접적으로 변경하지 않는다.
setState() 전의 상태와 후의 상태가 값이 ‘다르다면’ re-rendering이 일어난다.
불변성을 지키지 않고, 메모리 영역의 값을 직접 변경하면, 리엑트는 state가 바뀌었다고 인지하지 못한다.
→ 리엑트는 이전 state과 이후 state를 비교할 때, 얕은 비교(shallow compare)를 하기 때문이다.
🔖 원시형 타입의 값을 변경해보자
🎨 원시형 데이터를 변경해보자 (1)
+1 버튼을 누르면 count가 +1 이 되어 리렌더링 된다.
Show and Hide 버튼을 누르면 show가 true→ false, flase→true로 변하면서 리렌더링 된다.
🎨 원시형 데이터를 변경해보자 (2)
원시형 데이터 타입, number, boolen, string를 useState로 변경할때는 문제가 없다.
import React, { useState } from "react"
export default function Counter() {
const [count, setState] = useState(0)
const [show, setShow] = useState(true) //show가 true인 경우에만 보여진다.
const operators = ["+", "-", "*"]
const [operator, setOperators] = useState(operators[0])
return (
<div>
<button
onClick={() => {
let result;
if (operator === "+") result = count + 1
if (operator === "-") result = count - 1
if (operator === "*") result = count * 1
setState(result)
}}>
{operator}1
</button>
<br />
<button
onClick={() => {
setShow(!show)
}}>
Show and Hide
</button>
<button
onClick={() => {
const idx = Math.floor(Math.random() * operators.length)
setOperators(operators[idx])
}}>
Change Operator
</button>
<br />
{show && `Counter: ${count}`}
</div >
)
}
🔖 참조 타입의 값을 변경해보자
오브젝트에 변경된 값을 재할당 해서
오브젝트이므로 주소를 복사해서 리엑트가 변경된 사실을 알지 못한다.
🎨 오브젝트 데이터를 변경해보자(1)
새로운 객체를 만들어서
객체의 가상돔은 객체가 변경된 것을 인지하고, 렌더링을 해주게 된다.
true→ false로 변경, false→ true로 변경된 것을 볼수있다.
🎨 오브젝트 데이터를 변경해보자(2)
…인 스프레드 연산자를 이용해서 배열을 복사 한 후 복사한 값에 추가를 해야한다.
참조타입의 Array 변경하기
const [array, setArray] = uesState(["a", "b", "c", "d"])
잘못된 사용법
array[0] = "e"
const newArray = array
setArray[newArray]
-> array에 있는 값을 직접 변경하고
-> setArray를 통해서 값을 직접 변경한다.
-> 해당 방법은 array가 변경되었다는 것을 감지할수 없다.
올바른 사용법
setArray([...array, newItem])
setArray(array.filter(arr => {}))
-> 원본 데이터를 변경하지 않고 복사를 뜬 복사 값을 넘겨줘야한다.
🔖 props와 state 비교
props | state |
---|---|
부모 컴포넌트가 자식 컴포넌트에게 전달하는 값 | 자신(컴포넌트)이 스스로 관리하는 상태값 |
값을 자신(자식 컴포넌트)이 변경할 수 없음 | 값을 자신이 변경할 수 있음 |
공통
→ props를 통해 값을 내려받거나 자신이 관리하고 있는 state가 변경되면 컴포넌트 렌더링이 발생한다.
🔖 State를 올바르게 사용하기
1. 직접 State를 수정하지 마세요
이 코드는 컴포넌트를 다시 렌더링하지 않습니다.
// Wrong
this.state.comment = 'Hello';
-> 대신에 setState()를 사용합니다.
// Correct
-> this.setState({comment: 'Hello'});
2. 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
}));
number*2 를 반영하지 못한다.
현재의 데이터를 함수로 넘겨줘야 비동기적으로 실행될 수 있다.
위와 같은 표현식을 풀어서 쓰면 다음과 같다.
3. 데이터는 아래로 흐릅니다.
부모 컴포넌트나 자식 컴포넌트 모두 특정 컴포넌트가 유상태인지 또는 무상태인지 알 수 없고,
그들이 함수나 클래스로 정의되었는지에 대해서 관심을 가질 필요가 없습니다.
state가 소유하고 설정한 컴포넌트 이외에는 어떠한 컴포넌트에도 접근할 수 없습니다.
컴포넌트는 자신의 state를 자식 컴포넌트에 props로 전달할 수 있습니다.
<FormattedDate date={this.state.date} />
FormattedDate
컴포넌트는 date
를 자신의 props로 받을 것이고 이것이 Clock
의 state로부터 왔는지, Clock
의 props에서 왔는지, 수동으로 입력한 것인지 알지 못합니다.
function FormattedDate(props) {
return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}
이를 “하향식(top-down)” 또는 “단방향식” 데이터 흐름이라고 합니다
모든 state는 항상 특정한 컴포넌트가 소유하고 있으며 그 state로부터 파생된 UI 또는 데이터는 오직 트리구조에서 자신의 “아래”에 있는 컴포넌트에만 영향을 미칩니다.
🔖 State 끌어오기
한곳에서 state를 관리하는 방식이 ‘단일 진실 공급원’ 방식으로
데이터가 아래로 흘러야 한다는 리엑트의 추구 방향과 맞다.
'웹 개발 > React' 카테고리의 다른 글
[React] 컴포넌트 활용연습 : random-recommend (0) | 2022.06.20 |
---|---|
[React] useEffect란 무엇인가? (0) | 2022.06.13 |
[React] 생명주기(life cycle)란 무엇인가? (0) | 2022.06.13 |
[React] Compoenets와 Props란 무엇인가? (0) | 2022.06.13 |
[React] JSX란 무엇인가? (0) | 2022.06.13 |