리액트의 메인 기능은 UI를 렌더링하는 것과 동시에 사용자의 input에 따라 UI를 렌더링해주는 것.
리액트가 어플리케이션에서 주로 하는 일
1. JSX코드와 DOM을 평가하고 렌더링
2. state와 prop 관리(모든 컴포넌트에 필요한 데이터가 있는지, 사용자 입력을 올바르게 반영하고 있는지 확인하기 위함)
3. 컴포넌트와 관련 JSX코드를 재평가하고, 필요에 따라 실제 DOM을 조작할 수 있음
컴포넌트는 단지 함수이기 때문에 위에서 => 아래로 실행한다.
함수 안에 있는 모든 것은 결국 화면에 무언가를 가져오는것에 관한 것들.(click등의 사용자 입력에 반응하여)
* Side Effect
: 어플리케이션에서 일어나는 다른 모든 것들
ex) http 리퀘스트를 보내는 것, 로컬스토리지에 데이터 저장하는 것, 코드에서 타이머나 간격 설정, 잠재적 오류 해결
=> 전부 화면에 무언가를 가져오는 것과 직접적인 관계가 없다.(리액트를 사용하지 않음)
일반적인 컴포넌트 함수 밖에서 이루어져야한다.
const App = () => {};
export default App;
//밖에서 실행되어야 한다.
만약 직접 http 리퀘스트를 App 컴포넌트 함수 내부로 보내게 된다면,
함수가 다시 실행될 때 마다 http 리퀘스트를 다시 보내게 된다.
또한, state가 갱신될 때 마다 http 리퀘스트를 다시 보내게 됨.
=> http 리퀘스트에 대한 응답으로 어떤 state를 변경하게 된다면 무한루프에 빠지게 된다..
그래서 사이트 이펙트는 직접적으로 컴포넌트 함수에 들어가서는 안된다.
(버그나 무한루프에 빠질 수 있고, http 리퀘스트가 너무 많이 보내질 수도 있기 떄문.)
해결하기 위해서는 useEffect 훅을 사용하면 된다.(리액트 내장 훅)
*useEffect
Using the Effect Hook – React
A JavaScript library for building user interfaces
ko.reactjs.org
useEffect(() => {...}, [ dependencies ]);
useEffect는 두 개의 매개변수, 두 개의 인수와 같이 호출된다.
() => {...}
첫 번째 인수는 함수
모든 컴포넌트 평가 후에 실행되어야 하는 함수(지정된 의존성이 변경된 경우)
첫 번째 함수에 어떤 사이드 이펙트 코드도 넣을 수 있다.
이 사이드 이펙트 코드는 사용자가 지정한 의존성이 변경된 경우에만 실행된다.
컴포넌트가 다시 렌더링될 때는 실행되지 않는다.
[dependencies]
두 번째 인수는 지정된 의존성(의존성으로 구성된 배열)
import React, {useState} from 'react';
function App(){
const [isLoggedIn, setIsLoggedIn] = useState(false);
//저장되어있는지 확인하고
const storedLoggedInformations = localStorage.getItem('isLoggedIn');
//저장되어있으면 true로 설정한다.
if(storedLoggedInformations === '1'){
setIsLoggedIn(true);
}
}
예를들어 위처럼 작성한 코드로 접근해보면, 무한루프에 빠질 수 있는데
state가 갱신될 때 마다 App 함수 컴포넌트가 다시 실행되기 때문이다.
useEffect(()=>{
const storedUserLoggedInInformation = localStorage.getItem('IsLoggedIn');
//저장되었는지 확인하고,
if(storedUserLoggedInInformation === '1'){
//저장되어있으면 true로 설정한다
setIsLoggedIn(true);
}
},[]);
대신 useEffect를 사용하면 언제 실행될 지 제어할 수 있다.
useEffect함수 내부에 정의하면, 이 useEffect 함수는 리액트에서 실행하게 된다.
무한루프에 빠지지는 않을까?
=> 모든 컴포넌틀를 재평가 한 후에 실행되기 때문에 무한루프에 빠지지 않는다.
다만, 모든 컴포넌트를 평가한 후에 실행되는 것이 아니라, 지정된 의존성이 변경될 시에만 재평가한다.
ex) 앱을 다시 실행했을 경우 의존성이 변경된 것으로 간주되는데, 이는 의존성이 원래 없었기 때문이다.
위의 useEffect함수(익명함수)는 앱이 시작될 때 한번만 실행된다.
두번째 인자로 들어가는 의존성이 비어있기 때문에, 원래 의존성이 없던 상태에서 의존성이 없는 상태면 같은 상태이기 때문이다.
만약 앱이 시작될 때 딱 한번만 실행시키고 싶다면! useEffect를 사용하여 의존성이 빈 익명함수를 작성해주면 된다.
그러면 useEffect내부에 있는 코드들이 딱 한번만 실행된다.
이후에 실행되기를 원한다면 의존성을 변화시켜야하는데, 의존성을 비워뒀기 때문이다.
... 알파벳 대문자 소문자 잘 확인하자...
useEffect는 무언가에 대한 응답으로 실행되는 코드를 다루는데 도움이된다.
위의 예는 딱 한 번만 실행될 때를 가정했지만, 보통 한 번만 실행되길 원하지 않는다.
로그인 폼의 input에 들어가는 문자가 변경되었을 때 등의 경우에서 사용된다.
const [enteredEmail, setEnteredEmail] = useState('');
const [emailIsValid, setEmailIsValid] = useState();
const [enteredPassword, setEnteredPassword] = useState('');
const [passwordIsValid, setPasswordIsValid] = useState();
const [formIsValid, setFormIsValid] = useState(false);
useEffect(()=>{
setFormIsValid(
enteredEmail.includes('@') && enteredPassword.trim().length > 6
);
},[setFormIsValid, enteredEmail, enteredPassword]);
사실 setFormIsValid는 생략할 수 있다.
state업데이트 함수는 기본적으로 리액트에 의해 절대 변경되지 않도록 보장되기 때문.
setFormsValid와 같은 함수는 재렌더링 주기에 따라 변하지 않아서 생략할 수 있다.
(React는 해당 함수가 절대 변경되지 않도록 보장하므로 의존성으로 추가할 필요 없다.)
+) effect 함수에서 사용하는 "모든 상태변수와 함수"를 의존성으로 추가할 필요 없는 경우
1. fetch()나 localStorage와 같은 내장API 또는 함수를 추가할 필요 없다.
브라우저에 내장된 함수 및 기능에 따라 전역적으로 사용 가능하기 때문.
이러한 브라우저 API/전역 기능은 React 구성요소 렌더링 주기와 관련이 없고, 변경되지 않는다.
2. 변수나 함수를 추가할 필요 없다. 구성요소 외부에서 정의했기 때문. ex) 별도의 파일에 새 도우미 함수를 만드는 경우
이러한 함수 또는 변수도 구성요소 함수 내부에서 생성되지 않으므로 변경해도 구성 요소에 영향을 주지 않음
(해당 변수가 변경되는 경우, 또는 그 반대의 경우에도 구성 요소는 재평가되지 않는다.)
* effect함수에서 사용하는 모든 상태변수나 함수를 추가해야하지만,
구성요소(또는 일부 상위 구성요소)가 다시 렌더링 되어 이러한것들이 변경될 수 있는경우가 존재한다.
그래서, 컴포넌트 함수에 정의된 변수나 상태, 컴포넌트 함수에 정의된 props 또는 함수는 종속적으로 추가되어야 한다.
import { useEffect, useState } from 'react';
let myTimer;
const MyComponent = (props) => {
const [timerIsActive, setTimerIsActive] = useState(false);
const { timerDuration } = props; // using destructuring to pull out specific props values
useEffect(() => {
if (!timerIsActive) {
setTimerIsActive(true);
myTimer = setTimeout(() => {
setTimerIsActive(false);
}, timerDuration);
}
}, [timerIsActive, timerDuration]);
};
* timerIsActive : 의존성(종속성) 추가. 구성요소가 변경될 때 변경될 수 있는 구성요소상태이기 때문.(ex) 상태가 업데이트 되었기 때문)
* timerDuration : 의존성(종속성) 추가. 해당 구성요소의 props값이기 때문. 구성요소가 해당 값을 변경하면 변경될 수 있음.(이 컴포넌트 구성요소도 재렌더링되도록 한다.)
*setTimerIsActive : 의존성(종속성) 추가X. !!예외조건!!이기 때문에 추가하지 않음. 상태 업데이트 기능을 추가할 수 있지만 React는 기능 자체가 절대 변경되지 않음을 보장하므로 추가할 필요 없음.
*myTimer : 의존성(종속성) 추가X. 내장 API이기 때문. React 및 구성 요소와 독립적이며 변경되지 않는다.
* cleanUp
React - Effect Hook ( Clean-up )
이전 블로그에서 간단하게 짚고 넘어갔던 내용 중 Clean-up 함수라는 개념이 있다.Clean-up함수란,useEffect()에서 parameter로 넣은 함수의 return 함수이다.Component의 unmount이전 / update직전에 어떠한 작업을
velog.io
이해하는데 참고가 된 velog 감사합니다.
'FE·Client > React' 카테고리의 다른 글
[React] sh: react-scripts: command not found에러 (0) | 2023.01.29 |
---|---|
[React] useReducer() (0) | 2023.01.27 |
[React] Portals, Ref, uncontrolled component (0) | 2023.01.11 |
[React] 리액트 컴포넌트 스타일링, styled-components, 미디어쿼리, CSS 모듈 (0) | 2023.01.09 |
[React] 동적 배열 할당, 조건부 렌더링 (1) | 2023.01.06 |