let [아이템, 아이템변경] = useState(['냉면', '모밀', '초계국수']); <h1>{아이템[0]}</h1> // <h1>냉면</h1>
let [아이템, 아이템변경] = useState(['냉면', '모밀', '초계국수']); <h1>{아이템[0]}</h1> // <h1>냉면</h1> <button onClick={ () => { let copy = 아이템; copy[0] = '국수'; console.log(아이템 == copy) // true 반환, 기존과 신규 state가 같다 생각. 아이템변경(아이템); }}>텍스트 바꿀래</button>
이렇게 코드를 짜면 되겠지 하지만 변경 되지 않는다.
실제로 배열안에 첫번째 값을 냉면은 국수로 변경을 했지만
배열안에 데이터값만 변경한 것이지 아이템이라는 변수를 변경했다고 생각을 하지 않는다.
쉽게 말해 아이템이라는 변수는 배열안 값을 나타내는 화살표만 저장 한것이고, 배열 안의 값을 변경했다고 해도 화살표는 그대로이기 때문에
같다고 true를 반환 한다. 주소값이 다르다고 표현한다.
이런 이유는 리액트의 불변성과 관련이 있다. 아래 글 참고
let [아이템, 아이템변경] = useState(['냉면', '모밀', '초계국수']); <h1>{아이템[0]}</h1> // <h1>냉면</h1> <button onClick={ () => { let copy = [...아이템]; copy[0] = '국수'; console.log(아이템 == copy) // false 반환, 기존과 신규 state가 같지않으므로 state 변경 아이템변경(아이템); }}>텍스트 바꿀래</button>
- button을 클릭하면 h1태그 안의 기존의 내용인 '냉면'은 '국수'로 바뀌게 된다.
- 참조타입인 경우라서 새로운 배열을 만들고 기존의 배열은 건드리지 않는 ES6문법인 spread 연산자를 사용하면 된다.
let obj = { a: 1, b: 2 } obj.a = 7; console.log(obj) // {a:7, b:2}
이렇게 변수 obj에 대해서 실제로 수정이 됐지만,
리액트에서는 다르다.
let obj = { a: 1, b: 2 } obj = { ...obj, a: 7 } console.log(obj) // {a:7, b:2}
obj라는 변수의 객체를 변경 하고 싶다면
기존의 값을 복사하고 나서 원하는 값을 바꿔주어야 한다.
// 원시타입
const [number, setNumber] = useState(0)
setNumber(7)
// 참조타입
const [info, setInfo] = useState({ name: 'kim', age: 29 })
setState({...info, name: 'nam'})
리액트에서는 업데이트하기 위해서 js코드처럼 수정하면 안된다.
참조타입인 경우 새로운 객체나 배열을 생성한 후 값을 수정해야한다.
(spread연산자, map, filter, slice, reduce)
splice같은 메서드는 원본데이터를 변경하므로 X