React
[React] effect 이펙트란?
연어먹고싶음ㅁ
2023. 1. 16. 22:02
Side Effects: 어플리케이션에서 일어나는 모든것
ex) http 리퀘스트 보내기, 브라우저 장소에 저장하는 것
UseEffect 훅
// arg1. function
// arg2. 의존성
// 의존성이 변경될때만 arg1. function이 실행됨
useEffect(() => {...}, [dependencies]);
useEffect 사용 목적 : 사이드 이펙트를 처리하기 위함. ex) 이메일 주소/비밀번호 입력에 대해 유효성 검사
웹, 브라우저는 다시 로드될 때마다 최근의 데이터가 사라짐
리로드될 때 데이터가 사라지지 않고 유지하기 위해서 useEffect를 사용
useEffet 사용 전, 데이터 저장 방식
import React, { useState } from 'react';
import Login from './components/Login/Login';
import Home from './components/Home/Home';
import MainHeader from './components/MainHeader/MainHeader';
function App() {
//2. 데이터를 가져온다
const storedUserLoggedInInformation = localStorage.getItem('isLoggedIn');
// 3. isLoggedIn이 1(로그인을 이미 한 상태)이면, 바로 로그인..
if(storedUserLoggedInInformation === '1'){
setIsLoggedIn(true);
}
const [isLoggedIn, setIsLoggedIn] = useState(false);
const loginHandler = (email, password) => {
// We should of course check email and password
// But it's just a dummy/ demo anyways
//1. 데이터를 저장한다.
localStorage.setItem('isLoggedIn','1');
setIsLoggedIn(true);
};
const logoutHandler = () => {
setIsLoggedIn(false);
};
return (
<React.Fragment>
<MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
<main>
{!isLoggedIn && <Login onLogin={loginHandler} />}
{isLoggedIn && <Home onLogout={logoutHandler} />}
</main>
</React.Fragment>
);
}
export default App;
위와 같이 코드를 작성하면 개발자 도구에서 확인 가능
하지만 위의 코드에 문제점 있음
- 무한 루프를 만들 수 있음
데이터가 저장되어있는지 확인 > 저장되어있으면 setIsLoggedIn(true) 설정 > state 설정 함수를 호출할때마다 함수 자체가 재 실행됨 (이 과정의 무한루프)
useEffet 사용 후, 데이터 저장 방식
import React, { useState, useEffect } from "react";
import Login from "./components/Login/Login";
import Home from "./components/Home/Home";
import MainHeader from "./components/MainHeader/MainHeader";
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
// 이 함수는 리액트에 의해 실행 , 모든 컴포넌트 재평가 후에 실행 (의존성이 변한 경우만 실행)
// ex) 앱이 처음 실행될 때 - 의존성이 변경된 것으로 간주
// 이 함수 또한 앱이 시작될 때 한번만 실행됨
// 그 이후로 의존성이 변경되지 않기 때문
useEffect(() => {
const storedUserLoggedInInformation = localStorage.getItem("isLoggedIn");
if (storedUserLoggedInInformation === "1") {
setIsLoggedIn(true);
}
}, []);
const loginHandler = (email, password) => {
// We should of course check email and password
// But it's just a dummy/ demo anyways
localStorage.setItem("isLoggedIn", "1");
setIsLoggedIn(true);
};
const logoutHandler = () => {
// 로그아웃하면 데이터를 지움
localStorage.removeItem('isLoggedIn');
setIsLoggedIn(false);
};
return (
<React.Fragment>
<MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
<main>
{!isLoggedIn && <Login onLogin={loginHandler} />}
{isLoggedIn && <Home onLogout={logoutHandler} />}
</main>
</React.Fragment>
);
}
export default App;
useEffect 함수는 리액트에 의해 실행
모든 컴포넌트 재평가 후에 실행 (의존성이 변한 경우만 실행)
ex) 앱이 처음 실행될 때 - 의존성이 변경된 것으로 간주
이 함수 또한 앱이 시작될 때 한번만 실행됨. 그 이후로 의존성이 변경되지 않기 때문
위 코드의 문제점 : 키가 입력될 때마다 useEffect가 실행됨
해결방법 : 일정 시간동안 사용자가 입력하지 않으면, 그 때 키 유효성을 검사함
import React, { useState, useEffect } from "react";
import Card from "../UI/Card/Card";
import classes from "./Login.module.css";
import Button from "../UI/Button/Button";
const Login = (props) => {
const [enteredEmail, setEnteredEmail] = useState("");
const [emailIsValid, setEmailIsValid] = useState();
const [enteredPassword, setEnteredPassword] = useState("");
const [passwordIsValid, setPasswordIsValid] = useState();
const [formIsValid, setFormIsValid] = useState(false);
// 모든 로그인 컴포넌트 함수 실행 후에,
// [] 안의 요소가 컴포넌트 렌더링 주기에서 변경된 경우만 실행
useEffect(() => {
const identifier = setTimeout(() => {
setFormIsValid(
enteredEmail.target.value.includes("@") &&
enteredPassword.trim().length > 6
);
}, 500);
// 클린업 function
// useEffect가 다음번에 이 함수를 실행하기 전 이 함수가 실행 됨.
// 이펙트를 특정한 컴포넌트가 DOM 에서 마운트 해재할 때마다 > 컴포넌트가 재사용
// 모든 새로운 사이드 이펙트 함수가 실행되기 전에 , 컴포넌트가 실행되기 전에
// 처음 로드 될떄는 실행 안됨.
return () => {
// 새로운 타이머를 설정하기 전에 마지막 타이머를 지움
clearTimeout(identifier);
};
}, [enteredEmail, enteredPassword]);
const emailChangeHandler = (event) => {
setEnteredEmail(event.target.value);
};
const passwordChangeHandler = (event) => {
setEnteredPassword(event.target.value);
};
const validateEmailHandler = () => {
setEmailIsValid(enteredEmail.includes("@"));
};
const validatePasswordHandler = () => {
setPasswordIsValid(enteredPassword.trim().length > 6);
};
const submitHandler = (event) => {
event.preventDefault();
props.onLogin(enteredEmail, enteredPassword);
};
return (
<Card className={classes.login}>
<form onSubmit={submitHandler}>
<div
className={`${classes.control} ${
emailIsValid === false ? classes.invalid : ""
}`}
>
<label htmlFor="email">E-Mail</label>
<input
type="email"
id="email"
value={enteredEmail}
onChange={emailChangeHandler}
onBlur={validateEmailHandler}
/>
</div>
<div
className={`${classes.control} ${
passwordIsValid === false ? classes.invalid : ""
}`}
>
<label htmlFor="password">Password</label>
<input
type="password"
id="password"
value={enteredPassword}
onChange={passwordChangeHandler}
onBlur={validatePasswordHandler}
/>
</div>
<div className={classes.actions}>
<Button type="submit" className={classes.btn} disabled={!formIsValid}>
Login
</Button>
</div>
</form>
</Card>
);
};
export default Login;