๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ๋กœ ์ธํ•ด ์–ธ๋งˆ์šดํŠธ ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ

๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ๋กœ ์ธํ•ด ์–ธ๋งˆ์šดํŠธ ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ

์ƒ์„ฑ์ผ
Oct 25, 2021 07:02 AM
๊ธฐ๋ก์ž
ํ•ด๊ฒฐ ์—ฌ๋ถ€
ํ•ด๊ฒฐ ์—ฌ๋ถ€
์†์„ฑ
React
์นดํ…Œ๊ณ ๋ฆฌ

๐Ÿ” ๋ฐฐ๊ฒฝ ๋ฐ ๊ถ๊ธˆ์ฆ

๋กœ๊ทธ์ธ ํŽ˜์ด์ง€(/login)์—์„œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด history.push๋กœ ์ž๋™์œผ๋กœ ํ™ˆ ํŽ˜์ด์ง€(/)๋กœ ์ด๋™ํ•  ๋•Œ ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค
notion image
react_devtools_backend.js:2528 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function. at LoginForm (http://localhost:8000/main.bundle.js:4817:23) at LoginPage (http://localhost:8000/main.bundle.js:5169:73)

๐Ÿ“ข ํ•ด๊ฒฐ ๊ณผ์ •

ํ•ด๊ฒฐ์— ์˜๊ฐ์„ ์ค€ ์ž๋ฃŒ

notion image

๋ฌธ์ œ ์›์ธ

// useForm const handleSubmit = async (e) => { setIsLoading(true); e.preventDefault(); const newErrors = validate(values); if (Object.keys(newErrors).length === 0) { await onSubmit(values); } setErrors(newErrors); setIsLoading(false); };
  • useForm์—์„œ setErrors์™€ setIsLoading ํ•˜๊ธฐ ์ „์— onSubmit ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค
  • ๋ฌธ์ œ๋Š” onSubmit ํ•จ์ˆ˜๋Š” handleLogin์„ ์ „๋‹ฌ๋ฐ›๋Š”๋ฐ handleLogin ๋‚ด๋ถ€์—์„œ๋Š” history.push๋กœ ๋ผ์šฐํŒ…์„ ํ•˜์—ฌ setErrors์™€ setIsLoading์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— ๋ผ์šฐํŒ…์œผ๋กœ ์ธํ•ด ํผ ์ปดํฌ๋„ŒํŠธ๊ฐ€ unmount ๋œ๋‹ค๋Š” ์ ์ด๋‹ค
// LoginPage const handleLogin = async (loginFields) => { try { const userInfo = await postLogin(loginFields); if (userInfo.token) { fillUserInfo(userInfo); history.push('/'); } } catch (error) { // TODO: alert๋ฅผ ํ† ์ŠคํŠธ๋กœ ๊ต์ฒดํ•œ๋‹ค // eslint-disable-next-line no-alert alert(error.response.data); } };

ํ•ด๊ฒฐ์ฑ…

  • ๋”ฐ๋ผ์„œ setErrors์™€ setIsLoading์„ ๋ชจ๋‘ ๋งˆ๋ฌด๋ฆฌํ•œ ํ›„์— history.push๋กœ ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ๋ฉด ๋ชจ๋“  ๊ฒŒ ํ•ด๊ฒฐ๋œ๋‹ค
  • ๊ทธ๋Ÿฌ๋‚˜ ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ๋ฅผ useForm ๋‚ด๋ถ€๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์€ ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ ์ธก๋ฉด์—์„œ ๋ถˆํ•ฉ๋ฆฌํ•˜๋‹ค๊ณ  ํŒ๋‹จํ–ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ๋Š” ๋กœ๊ทธ์ธ API(postLogin)๊ฐ€ ์„ฑ๊ณตํ–ˆ์„ ๋•Œ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š”๋ฐ useForm์€ ๋น„๋™๊ธฐ ๋กœ๊ทธ์ธ API์˜ ์กด์žฌ๋ฅผ ์•Œ์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
  • ๊ทธ๋ž˜์„œ ์šฐ์„  ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฒ˜๋ฆฌ ํ•  ์ˆ˜ ์žˆ๋Š” setError๋ฅผ onSubmit ์‹คํ–‰ ์ด์ „์œผ๋กœ ์ˆœ์„œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ๋ถ€ํ„ฐ ์ง„ํ–‰ํ–ˆ๋‹ค
  • ๋กœ๋”ฉ ์ฒ˜๋ฆฌ(setIsLoading)๋Š” ๋น„๋™๊ธฐ ๋กœ๊ทธ์ธ ํ•จ์ˆ˜๊ฐ€ ๋๋‚œ ์ดํ›„์— ๋™์ž‘ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด ๋ถ„๋ช…ํ–ˆ์œผ๋ฏ€๋กœ onSubmit ํ•จ์ˆ˜ ์•ˆ์—์„œ ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ ๋บ๋‹ค
  • ๊ทธ๋ฆฌ๊ณ  ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ๋ฅผ ๋กœ๊ทธ์ธ API์˜ ์„ฑ๊ณต์—ฌ๋ถ€๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ useEffect๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹คํ–‰ํ•˜๋„๋ก ํ–ˆ๋‹ค
// useForm const handleSubmit = async (e) => { setIsLoading(true); e.preventDefault(); const newErrors = validate(values); setErrors(newErrors); if (Object.keys(newErrors).length === 0) { await onSubmit(values); } setIsLoading(false); };
// LoginPage const { userInfo, fillUserInfo } = useUserInfo(); //... const handleLogin = async (loginFields) => { try { const newUserInfo = await postLogin(loginFields); if (newUserInfo.token) { fillUserInfo(newUserInfo); } } catch (error) { // TODO: alert๋ฅผ ํ† ์ŠคํŠธ๋กœ ๊ต์ฒดํ•œ๋‹ค // eslint-disable-next-line no-alert alert(error.response.data); } }; //... useEffect(() => { if (userInfo.token) { history.push('/'); } }, [history, userInfo.token]);

ํ•ด๊ฒฐ์€ ๋˜์—ˆ์ง€๋งŒ ์•„์ง ์ž˜ ์ดํ•ด๊ฐ€ ์•ˆ๋˜๋Š” ๋ถ€๋ถ„

useForm์˜ setLoading๊ณผ useEffect์˜ ์‹คํ–‰ ์ˆœ์„œ๊ฐ€ ์˜ˆ์ƒ๊ณผ ๋งŽ์ด ๋‹ค๋ฅด๋‹ค
notion image
notion image
notion image

๋˜ ๋‹ค๋ฅธ ํ•ด๊ฒฐ์ฑ… (์™œ ํ•ด๊ฒฐ๋˜๋Š”์ง€๋Š” ์•„์ง ๋ชจ๋ฆ„)

import { useState, useEffect } from 'react'; const useForm = ({ initialValues, onSubmit, validate }) => { const [values, setValues] = useState(initialValues); const [errors, setErrors] = useState({}); const [isLoading, setIsLoading] = useState(false); useEffect(() => { return () => {}; }, [isLoading]); const handleChange = (e) => { const { name, value } = e.target; setValues({ ...values, [name]: value }); }; const handleSubmit = async (e) => { setIsLoading(true); e.preventDefault(); const newErrors = validate(values); setErrors(newErrors); if (Object.keys(newErrors).length === 0) { await onSubmit(values); } setIsLoading(false); }; return { values, errors, isLoading, handleChange, handleSubmit, }; }; export default useForm;