밝을희 클태

[react native / 리액트 네이티브] UseState 본문

마모리(My Memory) 프로젝트

[react native / 리액트 네이티브] UseState

huipark 2023. 7. 13. 18:25

프로젝트를 진행하면서 react native 0.71.8을 사용하고 있었는데
0.72.1 버전으로 업그레이드를 했다

그런데 코드에 아무 변화가 없는데 버전을 업데이트하고 나서 잘 작동하던 앱이 먹통이 됐다

증상

  • useState 변수들의 상태가 변하지 않음
  • 코드에 변수나 Text를 수정할 때 실행되는 hot reload에는 앱이 계속 먹통이지만 console.log를 코드의 아무 곳에 나 추가하면 앱이 너무나 잘 작동함

 

당연히 기존에는 잘 돼서 코드 문제 일 거라곤 전혀 상상도 못 하고 애꿎은 라이브러리들을 탓하면서 삭제하고 새로 깔고 버전 다운그레이드 하고 거의 이틀을 이 짓만 했다

끝내 라이브러리들은 문제가 없음을 확인하고 코드를 들여다보기 시작했는데

 

...


const [isSwitch, setIsSwitch] = useState(false);
const [todos, setTodos] = useState([]);


...

const toggleCheck = async (index) => {
    const newTodos = [...todos];
    newTodos[index].isSwitch = !newTodos[index].isSwitch;
    setTodos(newTodos);
    await saveTodos(newTodos);
}

...
 
 

 

toggleCheck 함수가 문제였다 당연히 토글 체크가 안 먹혀서 문제였던 건데 찾는 데 너무 오래 걸렸다.

 

const toggleCheck = async (index) => {
    const newTodos = [...todos];
    console.log("newTodos === todos = ", newTodos === todos);
    console.log(
    "newTodos[index] === todos[index] = ",
    newTodos[index] === todos[index]
);
 
newTodos[index].isSwitch = !newTodos[index].isSwitch;
setTodos(newTodos);
await saveTodos(newTodos);

 

여기서 내가 스프레드 연산자를 사용해서 newTodos를 초기화해 주었는데


newTodos === todos // false 가 나와서 당연히 다른 배열인 줄 알았다 그런데


newTodos[index]의 객체를 참조하면 원본인 todos[index]를 건드리게 되는 것이었다.

 

원시 타입(Primitive type)인 불린(Boolean), 숫자(Number), 문자열(String), null, undefined 등은 스프레드 연산자를 사용해서 할당받은 변수의 값을 바꿔도 원본은 바뀌지 않는다

 

let originalArray = [1, 2, 3];
let copiedArray = [...originalArray];

copiedArray[0] = 100;

console.log(originalArray); // [1, 2, 3]
console.log(copiedArray); // [100, 2, 3]

 

하지만 배열의 원소들이 객체일 경우에는 원본 배열과 복사된 배열이 동일한 객체를 참조하게 된다

 

let a = { name: "Alice" };
let b = a; // 'b'는 'a'와 동일한 객체를 참조

b.name = "Bob"; // 'b'를 통해 객체를 변경

console.log(a.name); // 이것은 'Bob'을 출력

 

그래서 객체 내부의 내가 바꿀려던 Swtich는 useState 값이었기 때문에! 연산자를 사용해서 바꿀 수가 없던 거였다...

그래서 수정한 코드가 깊은 복사를 이용해서 값을 수정하고 저장을 하게 했다

깊은 복사를 위해서는 JSON.parse(JSON.stringify(todos))와 같은 방법을 사용할 수 있다

 

const newTodos = JSON.parse(JSON.stringify(todos));
newTodos[index].isSwitch = !newTodos[index].isSwitch;
setTodos(newTodos);
await saveTodos(newTodos);

근데 아직도 왜 console.log로 인한 hot reload가 일어나면 잘 되는지 모르겠다.