개발자

useState와 useEffect에 대해 너무 헷갈립니다.

2024년 06월 24일조회 137

안녕하세요 useState와 useEffect를 공부중인데 아직 초보자라 너무 헷갈리더라구요. 제가 이해한 것은 우선 useState는 클릭했을 때 모달창이 나온다거나, 사용자가 input에 입력한 값처럼 무언가를 동적으로 변경이 되게 할 때 사용하고 또 API를 사용할 때 이 데이터를 저장할 때 사용한다...로 알고 있고 useEffect는 컴포넌트가 처음 렌더링 될 때 html 부분이 먼저 화면에 그려진 후 데이터가 실행되게 할 때 useEffect를 사용한다...까지만 이해하고 있습니다. 여기서 궁금한점이 첫번째로, useState는 제가 설명한대로만 사용하면 되는지 궁금합니다. 두번째로, useEffect는 이 안에 작성한 코드는 한번만 실행이 된다라고 하는데 이 한번만 실행이 된다라는게 무슨 말인지 그리고 useEffect안에 console.log()와 useEffect 밖에 console.log() 이렇게 했을 땐 뭐가 다른것인지 너무 헷갈립니다. 제가 아직 초보자라 정말 정말 쉽게 설명해주시면 너무 감사드리겠습니다. ㅜㅜ

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

답변 3

용용님의 프로필 사진

1. useState useState의 값이 변경되면 렌더링을 발생시킵니다 가상돔이 렌더링이 발생될 상황에 놓이면 해당 바뀐부분만 적절하게 비교한 후 업데이트 하게 되어 화면에 보여지게 됩니다 그래서 말씀하신 것처럼 동적으로 새로운 값으로 새로운 화면을 보여줘야 할 때 사용되는 것이 일반적입니다. 2.useEffect useEffect의 두번째 인자로 빈 배열을 넣어주게 되면 최초 마운트에 useEffect 첫번째 인자로 전달한 콜백함수가 한 번 실행됩니다 두번째 인자의 배열로 값을 넣어주면 해당 값이 변경될 때마다 useEffect가 실행됩니다 useEffect 외부(컴포넌트 내) console.log를 하게 되면 렌더링이 발생할 때마다 console.log가 실행됩니다. — 사실 위 내용 관련해서는 리액트 공식문서에 정말 친절하게 설명이 되어있습니다. 한국어로도 잘 되어 있으니 꼭 한번 확인해보시길 추천드립니다! 제가 언급한 키워드 중 리액트 가상돔과 추가로 useRef에 대해서도 꼭 찾아보시면 도움이 될 거 같아요

profile picture

익명

작성자

2024년 06월 25일

친절하게 답변해주셔서 너무 감사드립니다. useRef에 대해서도 바로 공부를 해봐야겟네요^^

문정동개발자님의 프로필 사진

저는 개인적으로 개념에대해서 정확하진 않더라도 일단 쉽게 이해가고 가면 좀 편하더라구요. 리액트는 화면을 필요할때만 렌더링 합니다. 화면에 필요한 정보들을 리엑트가 전부 가지고있고 그 정보를 통해 화면을 사용자들에게 보여줍니다. 이때 정보를 사용자들이 볼 수 있게 바꾸는 과정을 렌더링이라고 생각하시면 좋을 것 같습니다. 그러면 "필요할때" 라는걸 어떻게 판단할지 정해야겠죠? 예를들어 버튼을 클릭하면 버튼의 배경색이 빨강,파랑으로 번갈아가며 변하는 사이트를 만들고 싶다고하면 화면을 언제 렌더링 하면 좋을까요? 1. 버튼을 클릭할때 마다 사이트를 렌더링한다. 2. 버튼색이 바뀔때마다 사이트를 렌더링한다. 둘중 하나의 조건에서 렌더링해주면 되겠죠. 그런데 그 1번같은 경우에는 버튼을 클릭을 한 뒤에 무슨일이 일어날지도 모르는데 항상 렌더링을 한다는건 최적화 측면에서 너무나도 잃는게 많겠죠 하지만 2번으로 결정한다면 실제로 사용자가 변화를 봐야할때 바꾸는 것이기 때문에 꼭 필요할때만 바꿀 수 있을것입니다. 그래서 리액트는 2번을 채택했고 이를 좀더 정교하게 아래와 같이 생각했습니다. 화면에서 새롭게 랜더링해야 하는 요소들이 현재 어떤 상태인지를 보다가 상태바 견하면 화면을 바꿔야지(ex 버튼의 배경색이 빨간색인 상태에서 파란색인 상태로변경 등) 상태가 영어로 State죠 그래서 useState는 내가 상태를 쓰겠다는 겁니다. 그래서 버튼의 배경색이 바뀔떄마다 렌더링을 새로하고싶다면 버튼이 어떤 상태인지를 나타내는 변수를 사용할거고 그래서 use(사용하다) State(상태를) 이라고 생각하시면 편하실 것 같아요 그럼 const [btnBgColor,setBtnBgColor] = useState('red') 이런식으로 해서 버튼 컴포넌트에 잘 연결해 놓는다면 배경색이 red에서 blue로 변하면 아 어떤 상태가 변했다는걸 리액트가 인식하고 렌더링을 새롭게 하는겁니다. 다음으로 useEffect의 의미를 이해하시려면 side Effect라는 용어를 먼저 알아야 하는데요 사이드 이펙트는 쉽게 생각하면 특정 작업1을 했을때 내가 의도한바와 상관없이 일어나는 부작용 이라고 생각하면 될 것 같습니다. 이번에는 조금 복잡하게 부모 컴포넌트에 버튼 빨강,파랑으로 변하는 버튼1이 있고, 자식 컴포넌트에는 부모 컴포넌트에 있는 버튼색에 노랑이나 흰색을 섞어서 보여주는 버튼2가 있다고 생각해봅시다. 버튼1은 이전처럼 클릭할 때마다 빨강,파랑으로 바뀌고 버튼2는 섞을색을 노랑,흰색으로 바꿔줍니다. 그럼 버튼1이 빨간색이고 섞는색이 흰색이면 버튼2는 분홍색 버튼1이 빨간색이고 섞는색이 노랑이면 버튼2는 주황색 버튼1이 파란색이고 섞는색이 흰색이면 버튼2는 하늘색 버튼1이 파란색이고 섞는색이 노랑이면 버튼2는 초록색 이렇게 버튼2는 네가지 색이 있을 수 있겠죠 이때 화면의 상태는 3가지입니다. 1. 버튼1의 배경색 2. 섞을 색 3. 버튼2의 배경색 그런데 버튼1을 누르면 어떻게 될까요? 리액트는 화면 최적화를 위해서 상태가 변한 부분만 렌더링을 하기때문에 버튼1의 색만 바꾸게됩니다. 하지만 실제로는 버튼1의 배경색에 버튼2의 배경색이 영향을 받기 때문에 버튼2의 배경색도 바꿔줘야하죠 이렇게 우리는 버튼1의 배경색이라는 상태를 바꿨는데 다른 부작용이 발생하게되고 이런걸 side Effect라고 합니다. 그리고 이 side Effect를 컨트롤하기위해 사용하는게 useEffect입니다. 한글로 먼저 하고싶은 작업을 말해보면 '버튼1의 배경색이나 섞을색이 바뀔 때마다 두 색을 섞어서 버튼2의 배경색을 바꾼다' 입니다. useEffect를 사용하려면 아래와같이 함수하나와 배열하나가 필요한데요 useEffect(()=>{},[]) 여기서 '[버튼1의 배경색] 이나 [섞을색]이 바뀔 때 마다' 처럼 조건이 되는 상태를 의존한다 라고 표현하고 의존성 배열에 넣어줍니다. useEffect(()=>{},[btn1BgColor,mixColor]) 그리고 함수는 나머지부분 '두 색을 섞어서 버튼2의 배경색을 바꾼다' 를 함수로 만들어서 작성해주면 됩니다. useEffect(()=>{ // btn1BgColor과 mixColor를 섞은 색을 setBtn2BgColor를통해 상태를 변경하는 로직 },[btn1BgColor,mixColor]) 이렇게 useState와 useEffect는 상태,사이드이펙트 라는 개념을 숙지하시면 훨씬 이해가 쉽게 되실 것 같습니다. 중간에 생략한 부분이 많아서 이해가 안가시거나 혹시 더 궁금한점이 있으시면 편하게 말씀해주세요!

profile picture

익명

작성자

2024년 06월 25일

안녕하세요 답변주셔서 감사드립니다. 제가 아직 초보자라 조금 헷갈리는데 특히 useEffect에 대해서 조금 헷갈리더라구요. 리액트에서 화면을 우선 보여줘야되니 html부터 실행이 되고 그다음 useEffect를 사용해서 데이터를 불러온다까지만 알고 있는데 useEffect는 해당 컴포넌트로 가면 한번만 실행이 된다라고 되어있더라구요 이 한번만 실행이 된다라는게 무슨 의미인지 잘 모르겠습니다 ㅜㅜ 그리고 예를 들어 Dtail이라는 컴포넌트에 useEffect안에 console.log("안녕")이 있고 useEffect 밖에도 console.log("안녕") 이렇게 있어도 둘 다 콘솔에 찍히더라구요. 그래서 차이점이 뭔지 조금 헷갈립니다 ㅜㅜ

문정동개발자님의 프로필 사진

문정동개발자

프론트엔드2024년 06월 26일

사이드이펙트 부분을 조금 더 자세히 설명드릴게요 함수형 프로그래밍 패러다임안에서 순수함수 라는 개념이 있습니다. 순수함수란 동일한 파라미터를 전달했을 때 항상 같은값을 리턴해주는 함수를 말합니다. 예를들어 const add = (x,y) => x+y; 를 보면 add라는 함수에 1과,2를 파라미터로 넘겨주면 항상 3을 리턴합니다. add는 순수함수입니다. 다음으로 let x = 0; const add2 = y => x= x+y 를 보면 add2에 1을 파라미터로 넘기면 1을 리턴합니다. 그리고 한번 더 1을 파라미터로 넘기면 2를 리턴합니다. 같은값을 넘겨줬는데 응답이 다르죠? add2는 순수함수가 아니고 사이드이펙트(x의 값을 바꾸는)가 발생했다고 합니다. 쉽게 생각하시면 사이드이펙트는 함수 바깥의 값을 사용하려고하면 발생한다 라고 생각하시면 될 것같습니다. 그렇다면 리액트 함수형 컴포넌트 관점에서 보겠습니다. 작성자님께서 "useEffect를 사용해서 데이터를 불러온다" 라고 하셨죠? 그 이유는 우선 리액트 컴포넌트는 기본적으로는 순수함수로 되어있습니다. const MyComponent = ({title}) => <div>{title}</div> 위 MyComponent를 보시면 동일한 타이틀을 넘겨주면 항상 화면에서는 동일한 텍스트가 div안에 렌더링 될것입니다. 순수함수죠 그런데 데이터를 받아오는 경우를 생각해 보겠습니다. const MyComponent2 = ({title}) =>{ const version = await fetch... /// 타이틀을 서버로부터 받아오는 작업 return <div>{title} - version{version}</div> } 위 MyComponent2를 보시면 동일한 타이틀을 넘겨주더라도 서버로부터 받는 값에 따라 다른 텍스트가 div안에 렌더링되게 되겠죠? 이는 순수함수가 아닙니다. 아까 사이드이펙트는 함수 바깥의 값을 사용하려고하면 발생한다고했죠? 그래서 const version = await fetch... /// 타이틀을 서버로부터 받아오는 작업 이부분이 사이드이펙트를 발생시키는 부분이 되는거고 이부분을 처리하기 위해서 useEffect를 사용하기로 한겁니다. 리액트에서 사이드 이펙트를 하기위해 사이드 이펙트를 발생시킬 수 있는 부분은 useEffect안에서 하자 라고 정한겁니다. 질문자님의 질문을 보겠습니다. console.log는 순수함수일까요 아닐까요? 'a'를 넘겨주면 항상 a를 콘솔에 찍어주는 순수함수입니다. 사이드이펙트를 발생시키지 않기 때문에 useEffect안에서쓰든 밖에서 쓰든 상관없습니다.

박정환님의 프로필 사진

이해하시기 쉽게 설명을 드려보겠습니다. java나 c에서 init 이라는 함수를 혹시 아시나요? 초기화한다는 뜻이죠. 이 함수의 특징은 처음 소스가 불러와질 때(렌더링 될 때) 딱 한번만 처리됩니다. useEffect는 이것과 비슷한 개념입니다. 단, useEffect 선언문에 빈 배열을 넣었을 때만요. useEffect(() => {},[]) 근데 여기에 더해서 어떤 변수의 값을 구독하는 느낌으로도 쓰여집니다. useEffect 선언문에 변수를 (배열로) 넣을 수가 있죠. useEffect(() => {},[userList]) 또 있습니다. 선언문에 아무것도 넣지 않을 수도 있어요. 이러면 무한대로 작동됩니다. useEffect(() => {}) 이 3가지의 특징을 모두 갖고 있는게 useEffect입니다. 제가 말한 케이스를 한번씩 써보세요. 이해가 될겁니다. useState는 선언 자체가 useEffect랑 다릅니다. 변수와 set이 필요하죠. const [userList, setUserList] = useState([]) 그리고 이렇게 선언한 set변수 (setUserList) 를 실행시킬때 state를 사용해 user의 값이 변동되고, 리렌더링이 일어납니다. 정리하면 useEffect 자체가 많은 특징을 가지고 있어서 한번에 알아먹기 어려울 수 있습니다. 이렇게 한번씩 써보셔야 차이를 알 수 있습니다. 질문자님이 헷갈리는 부분에 대해 얘기를 해볼게요. Detail 이라는 컴포넌트 안에 useEffect 를 쓰고, 그 안에 console.log('안녕') 을 선언했습니다. 근데 useEffect 밖에도 console.log('안녕')을 쓰게 되면 안녕 안녕 두번 나오기 때문에 헷갈린다는 거죠? 이것은 컴포넌트 자체가 함수라서 나오는 증상이라고 할 수 있습니다. 함수 선언을 했기 때문에 console.log를 찍을 수 있는 거구요 함수가 불러와졌기 때문에(렌더링 됐기 때문에) 작동한겁니다. 그리고 useEffect까지 사용하였죠. 처음이니 두번 나오는게 맞습니다. 디버깅을 쉽게 하기 위해서 useEffect 안의 console.log는 내용을 변경하여 보세요. console.log('안녕111') 그 후 useEffect의 선언문 안에 변수를 넣어 보세요. useState로 선언한 아무 변수나 넣으면 됩니다. 그리고 버튼 클릭 등을 통해서 set을 실행해 보세요. 그럼 '안녕'과 '안녕111'의 차이를 알 수 있습니다. ('안녕'이 안나올거에요) 이처럼 set변수를 이용해 구독시킨 useEffect는 성격이 다른 것을 알 수 있을 겁니다. 대략 설명하였는데 직접 해보시고 파악하셨으면 좋겠습니다.

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

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

또는

이미 회원이신가요?

AI 답변
커리어리 AI 봇 프로필 이미지

커리어리 AI 봇

GPT가 달아주는 답변입니다.

2024년 06월 24일

React Hooks인 useState와 useEffect는 매우 중요한 개념입니다. 먼저, useState에 대해 설명하겠습니다. 당신이 이해하신 것처럼 useState Hook은 컴포넌트의 상태를 추가할 수 있게 해줍니다. React에서 "상태"란 필요에 따라 데이터를 변화시킬 수 있는 저장 공간을 의미합니다. 예를 들어 버튼 클릭이나 유저 입력 등으로 인해 변경되어야 하는 값들을 관리하는데 사용됩니다. 다음으로, useEffect에 대해 설명하겠습니다. useEffect Hook은 React 컴포넌트가 랜더링 될 때마다 자동으로 실행됩니다. 하지만, 두 번째 매개변수인 dependency array(의존성 배열)을 전달함으로써, 특정 값이 변경될 때만 effect를 실행하게 할 수 있습니다. 즉, useEffect 안에 작성된 코드는 컴포넌트가 처음 랜더링 될 때 한 번 실행되고, 그 다음부터는 의존성 배열 안의 값이 변경될 때만 재실행되게 합니다. 반면에 useEffect 밖에서 console.log()를 호출한다면, 해당 함수는 컴포넌트가 리렌더링 될 때마다 호출됩니다. 예를 들어 다음과 같은 코드가 있다고 해봅시다: ```javascript const [count, setCount] = useState(0); console.log('Rendering component', count); useEffect(() => { console.log('Component did mount or count changed', count); }, [count]); ``` 여기서 'Rendering component' 메시지는 컴포넌트가 리렌더링 될 때 마다 출력되고, 'Component did mount or count changed' 메시지는 컴포넌트가 처음 마운트 되거나 `count` 값이 변경될 때 출력됩니다. 즉 useEffect 안의 코드와 밖의 코드 차이는 실행 시점에 있습니다. useEffect 안의 코드는 특정 값이 변경되었을 때만 재실행되고, useEffect 밖의 코드는 항상 리렌더링 시점에 실행됩니다. 적절한 처리를 위해서 필요에 따라 useState와 useEffect를 사용하는 것이 중요합니다. 하나 더 친절한 점은 useEffect 내부에서 비동기 작업을 하는 경우 조심하셔야 한다는 것입니다. 기본적으로 useEffect 콜백 함수에서 직접 비동기를 반환할 수 없으며 이럴 때는 아래와 같이 별도의 async 함수를 선언하여 사용합니다. ```javascript useEffect(() => { const fetchData = async () => { const response = await fetch(...); ... }; fetchData(); }, []); ```

목록으로

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