개발자

react의 setState가 정상동작하지 않아요.

2022년 10월 20일조회 215

react를 이용해 이것저것 테스트해보고 있는데요. 버튼을 눌렀을 때 state를 1 증가시키는 예제를 해보고 있습니다. const oneCountUp = () => { setCount(count + 1); }; 위처럼 1 증가시키는 함수를 정의해서 onClick에서 위의 함수를 호출하는 방식으로 했습니다. 근데 호기심에 3을 증가시켜보자 하고 oneCountUp을 3번 호출했습니다. 근데 여전히 1만 올라갑니다. 왜 그런걸까요??? import React, { useState } from 'react'; export default function CountTest() { const [count, setCount] = useState(1); const oneCountUp = () => { setCount(count + 1); }; return ( <div> <button onClick={() => { oneCountUp(); oneCountUp(); oneCountUp(); }} > 1 증가 </button> <p>{count}</p> </div> ); }

이 질문이 도움이 되었나요?
'추천해요' 버튼을 누르면 좋은 질문이 더 많은 사람에게 노출될 수 있어요. '보충이 필요해요' 버튼을 누르면 질문자에게 질문 내용 보충을 요청하는 알림이 가요.
profile picture
익명님의 질문

답변 1

엄홍재님의 프로필 사진

혹시 공식문서의 https://ko.reactjs.org/docs/faq-state.html#why-is-setstate-giving-me-the-wrong-value 이 부분을 보셨나요? 클래스 컴포넌트로 되어있긴한데 매우 유사한 상황인것 같습니다. 'setState 호출은 비동기적으로 이뤄집니다. 따라서 setState 호출 직후 새로운 값이 state 에 반영될 거라고 믿어서는 안 됩니다.' 라고 적혀있습니다. oneCountUp(); oneCountUp(); oneCountUp(); 이렇게 3번 호출 할 때 순차적으로 호출되고 끝나고 호출되고 끝나고가 아닌 비동기로 이루어져서 전부 현재 상태에서 1을 증가시키게 되는것으로 보입니다. 이걸 수정하려면 oneCountUp함수를 수정해야할 것 같아요 setState함수에는 값 말고 함수를 넘겨줄 수 있습니다. 그리고 함수의 첫번째 인자로 직전 state를 가지고 오게 됩니다. 그래서 아래처럼 변경하면 될 것 같네요 const oneCountUp = () => { setCount((beforeCount) => beforeCount + 1); };

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

비슷한 질문 2

Q. useRef의 작동방식이 궁금합니다

useRef를 통해 dom element에 접근하기도 하고, stale closure문제를 해결하는데에도 사용하는데, 실질적으로 어떻게 작동해서 이게 가능한지 궁금합니다.

안녕하세요! useRef를 통해 만들어지는 것은 JS의 객체와 유사하다고 보면 됩니다. useRef를 통해 만든 값이 일반 객체와 다른점은, 매 렌더링 시 동일한 객체를 제공하는 것입니다. - useRef<T>(initialValue: T): {current: T} - (참고: https://github.com/facebook/react/blob/fd31724d5d41a4df71af55f710b46562874511f9/packages/react-reconciler/src/ReactInternalTypes.js#L388) - (참고: https://ko.reactjs.org/docs/hooks-reference.html#useref) useRef를 통해 받은 값은 useRef가 사용된 컴포넌트의 라이프사이클 동안 사용할 수 있습니다. JSX에 특정 DOM 컴포넌트에 ref={useRef를 통해 받은 값}을 추가하시게 되면, 컴파일러가 JSX를 컴파일하면서 JS로 변환을 시켜주고 해당 JS를 브라우저가 실행하면서 값을 채워넣어주는 것으로 알고있습니다. (참고: https://ko.reactjs.org/docs/jsx-in-depth.html) stale closure의 경우는 useRef의 값이 항상 같은 객체이고 closure안에서는 이 객체를 "참조"하는 형식이기 때문에, 객체의 current 값이 바뀌면 closure 안에서도 바뀐 current 값을 사용할 수 있습니다. (reference 관련 so 글 참고: https://stackoverflow.com/questions/8318357/javascript-pointer-reference-craziness-can-someone-explain-this) 저도 질문에 답변하려고 여러가지 실험들을 해보았는데요. Functional component로 gist를 한번 만들어보았습니다. 저도 헷갈리는 부분이 있긴하지만 확실히 일반 JS 객체 대신 왜 useRef를 사용해야하는 이유를 알게된 것 같네요. (https://gist.github.com/json9512/ef28abf2429c639ccbdd6b48c7c3efe5) 결론은 useRef의 동작 방식이 가능한 이유는 JS에서 객체를 접근할때 참조 형식으로 접근한다는 점과 useRef를 통해 받은 객체가 항상 동일하다는 점 때문인 것 같습니다. 제가 참고했던 아티클들 첨부할게요. - https://dmitripavlutin.com/react-useref-guide/ - https://www.freecodecamp.org/news/react-under-the-hood/ - https://www.smashingmagazine.com/2020/11/react-useref-hook/ - https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Working_with_Objects#%EA%B0%9D%EC%B2%B4_%EA%B0%9C%EC%9A%94 - https://hewonjeong.github.io/deep-dive-how-do-react-hooks-really-work-ko/

이 질문 바로 가기

Q. react 그리드에서 수정된 부분이 있으면 조회버튼을 눌렀을 때 alert창 띄우기 기능 (useState 비동기 질문)

안녕하세요. react 초보 개발자입니다. 자바스크립트도 처음이라 비동기 관련해서 제 의도와는 다르게 작동할 때마다 당황하는 중입니다🤣 쌩초보임을 감안해 너그럽게 댓글 달아주시면 감사하겠습니다 :) 화면 설명 먼저 드리자면 조회 버튼을 누르면 그리드에 데이터가 뜨고, 데이터를 수정한 후에 저장할 수 있는 화면입니다! 제목과 같이 그리드에서 수정된 부분이 있을 경우에, 저장하지 않고 조회버튼을 누르면 '수정중입니다. 조회를 진행하시겠습니까?' 와 같은 alert창을 띄우는 기능을 구현중에 있습니다. 참고로 그리드는 aggrid 사용중입니다. 1. 우선 변경값 존재여부를 확인하는 변수 isChanged 를 useState로 선언해주었습니다. const [isChanged, setIsChanged] = useState<boolean>(false); 2. 그리드에서 수정된 부분이 있나 체크하는 건 onCellValueChanged 함수를 통해 값이 변경되면 isChanged가 true로 바뀌게 했습니다. const onCellValueChanged = (params: any) => { setIsChanged(true); }; 3. 저장로직에는 setIsChanged(false)가 있습니다. 또한 저장이 제대로 끝난 후에 조회로직을 탑니다. const onClickSave = async () => { // (생략) 저장 로직 // 저장 완료 후 setIsChanged(false); onClickSearch(); } 4. 조회로직에는 isChanged의 값을 확인하고, 변경값이 있다면 alert창이 뜨고, 확인을 누르면 조회를 진행합니다. const onClickSearch = async () => { if (isChanged) { // (생략) 메세지 띄우는 로직. alert창에서 확인을 누르면 조회 진행 setIsChanged(false); } // (생략) 조회 로직 } * 문제점 정상적으로 저장을 한 후에 조회로직을 타는데, isChanged가 false로 변경되기전에 조회로직을 타서 alert창이 뜹니다. 이 문제는 어떻게 해결하는 게 좋을까요..?

질문에 대해 정확하게 이해는 못했습니다. 죄송합니다.ㅜㅜ 추측해보면 setState에서 비동기가 문제가 될것 같습니다. setState를 여러번 실행하더라도 비동기로 동작하면서 값이 순서대로 변하지 않아 원하지 않는 로직대로 동작하지 않을 수 있습니다. 관련 내용: https://careerly.co.kr/qnas/865 해당 부분으로 문제를 해결할 수 있으면 좋겠네요.. 아니라면.. 질문을 좀더 상세히 코드도 올려주시면 감사하겠습니다. :)

외 1개 답변 보러 가기

목록으로
키워드로 질문 모아보기

실무, 커리어 고민이 있다면

새로운 질문 올리기

지금 가입하면 모든 질문의 답변을 볼 수 있어요!