๋ฐ์ ๋ฒ์ :
16.13.0
์ง์งํ๊ฒ, ๋ด๊ฐ ์ผํ๋ ํ์ฌ๋ ๊ทธ๊ฒ์ ์ ํ ๊ด์ฌ์ด ์์ต๋๋ค. ๋ถ๋ช ํ ๋๋ โโ์ผ์ฐ์ด ๊ฒฝ๊ณ ๋ฅผ ๋ฐ์๋ค๋ฉด ๊ทธ๋ฌํ ๊ฒฝ๊ณ ๊ฐ ๋ํ๋๋๋ก ํ ์ ์ด ์์ต๋๋ค. ํ์ฌ๋ก์๋ ์ค๋ฅ๋ฅผ ์์ ํ๋ ๊ฒ์ด ๋ถ๊ฐ๋ฅํ ์ ๋๋ก ์ด๋ ต์ต๋๋ค. ์๋ํ๋ฉด ์ ๋ ๋ง์ ๋ค๋ฅธ ๊ฒฝ์ฐ์ ๊ฑฐ๋ํ ์คํ ์ถ์ ์ผ๋ก ์ค๋ฅ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ํ๋๋ ์ค๋ฅ ์ค ํ๋ ์ด์์ ์์ ํ๋ ค๊ณ ์๋ํ์ง๋ง ์ด๋ฏธ ๋ง์ ์๊ฐ์ด ๊ฑธ๋ ธ์ต๋๋ค. ์ฌ์ฉ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ์ผ๋ถ๋ฅผ ๋๋ฒ๊ทธํ๋ ค๊ณ ์๋ํ์ง๋ง ์ด์ด ์์์ต๋๋ค.
ํ ๊ฐ์ง ์:
๊ฑฐ๊ธฐ์์ ์ฐ๋ฆฌ๋ ๊ตฌ์ ๋ฐ์ ๋ผ์ฐํฐ, ๊ตฌ์ redux-connect(๊ตฌ์ componentWillReceiveProps
๋ฉ์๋์ ์ค๋ฅ๋ฅผ ์์ ํ๊ธฐ ์ํด ํ๋ก์ ํธ ์์ค์ ๋ฃ์ด์ผ ํจ), recompose ๋ฑ์ ์ํด ์์ฑ๋ ์ผ๋ถ HOC์ ์ฌ์ฉ์ ์ ์ ์์ต๋๋ค. ๋ด๊ฐ ๊ฐ๋ฐํ ๊ตฌ์ฑ ์์๋ฅผ ์ดํด๋ณด๊ณ ๋ฒ๊ทธ๋ฅผ ์์ ํ๊ธฐ ์ํด setState
๋ฌธ์์ด๋ก ๊ฒ์ํ ์ ์๋ ๋จ์ํ ๊ฐ์ DOM ํธ๋ฆฌ๊ฐ ์๋๋ผ ํจ์ฌ ๋ ๋ณต์กํฉ๋๋ค.
์ด ์ค๋ฅ๋ฅผ ๋นํ์ฑํํ๊ฑฐ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์์น๋ฅผ ์ฐพ๋ ๋ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ ค๋ฉด "UNSAFE" ์ต์ ์ ๋ง๋์ธ์ ๐
์ด ๊ฒฝ๊ณ ๋ฅผ ๋ ์ผ์ฐ ์ถ๊ฐํ์ผ๋ฉด ํฉ๋๋ค. ์ฃ์กํฉ๋๋ค. Hooks์ ๋์ ์ผ๋ก ์ธํ ์ค์์์ต๋๋ค. ๋๋ ์ด๊ฒ์ด Hooks๋ฅผ ์ฌ์ฉํ๋ ์๋ก์ด ์ฝ๋๋ก ์ธํด ๋ฐ์ํด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ์๋ํ๋ฉด ํจ์ฌ ๋ ์ผ์ฐ ํด๋์ค์ ๋ํด ์ด๋ฏธ ๋์ผํ ๊ฒฝ๊ณ ๊ฐ ์์๊ธฐ ๋๋ฌธ์ ์ด์ ์ฝ๋์์๋ ์ด๋ฏธ ์ด ๊ฒฝ๊ณ ๋ฅผ ๋ณด์์ ๊ฒ์ ๋๋ค.
์ด๊ฒ์ ํฅํ ๋ฒ์ ์ React์์ ํ๋ ์คํจ๋ฅผ ์์ํ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. ์๋์ ์ด๋ ์๋๋ (์ด ํจํด์๋ ๋ง์ ๋ฒ๊ทธ๊ฐ ์์์ต๋๋ค). ๋ฐ๋ผ์ ๊ด๊ณ์์ด ๊ฒฐ๊ตญ ์ด์ ๋ฒ์ ์ ๊ฐํ ์ ์์ต๋๋ค. ๊ณ ์น ์ ์๋ค๋ฉด ์ด์ ๋ฒ์ ์ React์ ๊ณ ์ ํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๊ทธ๋ฌ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ฑ์์ ๋์์ ๋ฐ์ ์์ ๋ฒ์ ์ ๊ฒ์ํ ์ ์๋์ง ํ์ธํ๋ ๊ฒ์ ํฌํจํ์ฌ ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ์ต๋ํ ์ฝ๊ฒ ์์ ํ ์ ์๋๋ก ๋์๋๋ฆฌ๊ณ ์ ํฉ๋๋ค.
Chrome ์ฝ์์์ ์์ >
ํ์ดํ๋ฅผ ํ์ฅํ๋ฉด ์ถ๊ฐ ์คํ ์ถ์ ๋ ํ์๋์ด์ผ ํฉ๋๋ค(์คํฌ๋ฆฐ์ท์ ๊ตฌ์ฑ ์์ ์คํ ์ธ์). ๊ทธ๊ฒ๋ ์ฌ๋ ค์ฃผ์ค ์ ์๋์? ๊ทธ๋ฌ๋ฉด ๋ ๋๋ง์์ ๋ถ์์ฉ์ ์ผ์ผํค๋ ์ ํํ ํธ์ถ ์ฌ์ดํธ๊ฐ ํ์๋ฉ๋๋ค.
๋์ ํจ๊ป ์ด๊ฒ์ ๋ด๊ฐ formik์ ์ฌ์ฉํ ๋ ๋ํ๋ฉ๋๋ค.
@sebmarkbage ๋ต๋ณ ๊ฐ์ฌํฉ๋๋ค. >๋ฅผ ํด๋ฆญํ ํ ๋ํ๋๋ ์คํ ์ถ์ ์ ์ฐ์ค๊ฝ์ค๋ฝ์ต๋๋ค. 200๊ฐ ์ด์์ ํญ๋ชฉ์ด ํฌํจ๋์ด ์์ต๋๋ค!
๊ฑฐ๊ธฐ์ ๋ถ์ฌ ๋ฃ๊ฑฐ๋ pastebin์ ๋ํ ๋งํฌ๋ฅผ ์ ๊ณตํ๋ ค๊ณ ํ์ง๋ง ๋ค๋ฅธ ๋ฐฉํฅ์ผ๋ก ์๋ํ์ต๋๋ค. ์ผ๋ถ ์ฌ์ฉ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ Github ๋ฌธ์ ๋ฅผ ์ดํด๋ณด๊ณ ์ฉ์์ ์ค ํ๋๊ฐ redux-form( https://github.com/redux-form/redux-form/issues/4619) ์ด๋ผ๋ ๊ฒ์ ์์์ต๋๋ค
๊ทธ๋ฌ๋ ์ฌ์ ํ ์ด ๋ฌธ์ ๋ฅผ ๋ซ์ง ์๋๋ก ์์ฒญํ๊ณ ๋ค๋ฅธ ๊ฐ๋ฐ์์๊ฒ ์ด๋ฌํ ์ค๋ฅ๋ฅผ ์ผ์ผํค๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ๊ธฐ์์ ์ธ๊ธํ ๊ฒ์ ์ ์ํฉ๋๋ค.
@RodolfoSilva ๊ทธ๊ฒ์ด formik์ ์ํ ๊ฒ์ด๋ผ๊ณ ํ์ ํฉ๋๊น? ๊ทธ๋ ๋ค๋ฉด ๊ฑฐ๊ธฐ์์ ๋ฌธ์ ๋ฅผ ๋ง๋ค๊ณ ์ฌ๊ธฐ์ ๋ํ ๋งํฌ๋ฅผ ๊ฒ์ํ ์ ์์ต๋๊น? ๋ชฉ๋ก์ ํญ๋ชฉ์ด ๋ ๊ฐ ์ด์ ํฌํจ๋ ๊ฒฝ์ฐ ์ฒซ ๋ฒ์งธ ๋ฉ์์ง ์์ ๋ถ๋ถ์ ์ด๋ฌํ ๋ฌธ์ ๋ชฉ๋ก์ ๋ง๋ค๊ฒ ์ต๋๋ค.
์ด๊ฒ์ ์ ๋ง ๋นจ๋ฆฌ ํด๊ฒฐ๋์ด์ผ ํฉ๋๋ค. ์ ๊ทธ๋ ์ด๋๋ฅผ ๋ถ๊ฐ๋ฅํ๊ฒ ๋ง๋ญ๋๋ค. ์ค๋ฅ ์ถ์ ์ ๊ฑฐ์ ๋ถ๊ฐ๋ฅํฉ๋๋ค.
ํ . ์ค๋ฅ ๋ฉ์์ง์์ ์ฐพ์ ์ค์ ์ค๋ช ํ๋ ๊ฒ์ด ๋์์ด ๋ ์ง ๊ถ๊ธํฉ๋๋ค.
์ด ๊ฒฝ์ฐ ์ฐพ์ ์ฒซ ๋ฒ์งธ ์ค์ dispatchAction
๋ค์ ์ค์
๋๋ค. ๊ทธ๊ฒ์ด React๋ฅผ ํธ์ถํ๋ ๊ฒ์ด์ด์ผ ํฉ๋๋ค.
@RodolfoSilva ๊ณต์ ํ ์ ์๋ FormItemInput.js
์ ์ถ์ฒ๋ฅผ ๊ฒ์ํ ์ ์์ต๋๊น? 71ํ์์ dispatch ๋๋ setState๋ฅผ ํธ์ถํ๋ ๊ฒ ๊ฐ์ต๋๋ค.
์ค๋ฅ๋ฅผ ์ผ์ผํค๋ ์ฝ๋ ํ์ ์ ํํ ํฌํจํ๋๋ก ์ด ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์์ ํ๋ ๊ฒ์ด ํ์์ ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ๋ฌธ์ ์ ์์ธ์ด ๋ก์ปฌ ์ฝ๋์ธ์ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฝ๋์ธ์ง ์ ํํ ํ์
ํ๋ ๊ฒ์ ๊ฑฐ์ ๋ถ๊ฐ๋ฅํฉ๋๋ค. react-redux ๋ฐ react-router์ ๊ฐ์ ์ธ๋ถ ๊ฐ๋ฅ์ฑ ์ด ๋งค์ฐ
๋๋ ์ฌ๊ธฐ์ React-Redux๊ฐ ์๋ชป์ด ์๋๋ผ๊ณ ํ์ ํ์ง๋ง ์ค๋ฅ ๋ฉ์์ง์ ๊ตฌ์ฑ ์์ ์คํ์ด ์ค์ ๋ก ๋ฌด์จ ์ผ์ด ์ผ์ด๋๊ณ ์๋์ง ์๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ ๋ค๋ ๋ฐ ๋์ํ์ต๋๋ค.
๋๋ Redux-form๊ณผ ๊ฐ์ ๋ฌธ์ ์ ์ง๋ฉดํด ์์ต๋๋ค!
๋๋ ๊ฐ์ ๋ฌธ์ ๊ฐ ์์ผ๋ฉฐ ๋ด redux ํ๋ ์ ์ฒ์์ผ๋ก ์ธ ๋ ๋๋ ๋ชจ๋ ๊ฒ์
๋๋ ๊ทธ ๋ฌธ์ ๋ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ด๊ฒ์ ๋ด ๊ตฌ์ฑ ์์์ ๋๋ค.
`const [๊ฐ๊ฒฉ, setPrice] = useState(0);
const updatePrice = (newPrice) => {
setPrice(newPrice)
}
< CardContainer onPriceUpdated={updatePrice} > CardContainer >
`
๋ฐ๋ผ์ ์ด ๊ฒฝ์ฐ ๋ด CardContainer ๊ตฌ์ฑ ์์๋ ๊ฐ๊ฒฉ์ด ์
๋ฐ์ดํธ๋๊ณ ์์ ๊ตฌ์ฑ ์์๊ฐ ์ ์์๋ฅผ ๋ ๋๋งํ ๋ ์์ ๊ตฌ์ฑ ์์์ ์๋ฆฝ๋๋ค.
๊ทธ๋์ React๋ ๋ด๊ฐ ๋ค๋ฅธ ๊ตฌ์ฑ ์์์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ ๊ตฌ์ฑ ์์์ ์ํ๋ฅผ ์
๋ฐ์ดํธํ๋ ค๊ณ ํ๋ค๊ณ ๊ฒฝ๊ณ ํ๋ ๊ฒ ๊ฐ์ต๋๋ค.
๋๋ ๋ฐ์์ ์ต์ํ์ง ์์ผ๋ฏ๋ก ์ด๊ฒ์ด React ํจํด์ธ์ง ๋๋ ์ค์ ๋ก ๋ฒ๊ทธ์ธ์ง ํ์คํ์ง ์์ต๋๋ค.
์ด ๊ฒฝ๊ณ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ์ ์ ์ฌํญ์ด ์์ผ๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค.``
@l0gicgate
์ค๋ฅ๋ฅผ ์ผ์ผํค๋ ์ฝ๋ ํ์ ์ ํํ ํฌํจํ๋๋ก ์ด ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์์ ํ๋ ๊ฒ์ด ํ์์ ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
JavaScript๋ก ํ ์ ์๋ ์ผ์๋ ํ๊ณ๊ฐ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ชจ๋ ์ ๋ณด๋ ๋ธ๋ผ์ฐ์ ์์ ๋ณผ ์ ์๋ ์คํ์ ์์ต๋๋ค . React ๋ด๋ถ์ ์๋ ์ค์ ๊ฑด๋๋ฐ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
JavaScript ์คํ์ ๋ณด๋ ค๋ฉด ์ค๋ฅ ๋ฉ์์ง ์์ ์๋ ์์ ํ์ดํ ๋ฅผ ํฉ๋๋ค .
์๋ฅผ ๋ค์ด ์ด์ ์ ์ด ์คํฌ๋ฆฐ์ท์ ๋ณด์ญ์์ค.
์คํ์ ํํค์น๋ ๊ฒ์ด ์ฝ๊ฐ ์ฑ๊ฐ์ ์ผ์ด์ง๋ง ์ฒ์ ๋ช ํ๋ ์์ ๊ฑด๋๋ฐ๋ ๊ฒ์ ๊ทธ๋ ๊ฒ ์ด๋ ต์ง ์์์ผ ํฉ๋๋ค. ๋ฐ๋ก ๋ค์ ํ๋ ์์ด ๋ฌธ์ ์ ์์ธ์ ๋๋ค. ์ด ๊ฒฝ์ฐ Formik ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ด๋ถ์ ์๋ ๊ฒ์ฒ๋ผ ๋ณด์ ๋๋ค. ๋ฐ๋ผ์ ๋ฌธ์ ๋ฅผ ์ ๊ธฐํ ์ ์์ต๋๋ค.
@martinezwilmer ์ด ์์ ๋ ๋๋ฌด ์์์ ๋์์ด ๋์ง ์์ต๋๋ค. ์๋๋ฐ์ค๋ฅผ ๋ง๋ค์ด์ฃผ์ธ์.
๋ฏธ๋์ ๋๊ธ ์์ฑ์์๊ฒ. ์๋ก์ด ๊ฒฝ๊ณ ๊ฐ ํ์๋๋ ๊ฒ์ด ๋ต๋ตํ๋ค๋ ์ ์ ์ดํดํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ฝ๋์ ๋ฒ๊ทธ๋ฅผ ์ผ์ผํฌ ๊ฐ๋ฅ์ฑ์ด ์๋ ํฉ๋ฒ์ ์ธ ๋ฌธ์ ๋ฅผ ์ง์
์คํ ์ถ์ ์์ ์ถ์ฒ๋ฅผ ์ดํดํ ์ ์๋ ๊ฒฝ์ฐ ์คํฌ๋ฆฐ์ท์ ๊ฒ์ํ๊ฑฐ๋ ์ฌ์์ฐ ์๋๋ฐ์ค๋ฅผ ์์ฑํด ์ฃผ์๋ฉด ๋์๋๋ฆฌ๊ฒ ์ต๋๋ค. ๋๋ถ๋ถ์ ๋ช ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๊ฐ์ ธ์จ ๊ฒ์ผ ์ ์์ผ๋ฏ๋ก ๊ฐ์ฅ ์์ฐ์ ์ธ ๋ฐฉ๋ฒ์ ์ด๋ฌํ ๊ฒฝ์ฐ๋ฅผ ์ค์ด๊ณ ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ฌธ์ ๋ฅผ ์ ๊ธฐํ๋ ๊ฒ์ ๋๋ค.
๋ค๋ค ๊ฐ์ฌ ํด์.
์ฌ๊ธฐ์์ ๊ฒฝ๊ณ ์ ๊ด๋ จ๋ ์ ํํ ๋ผ์ธ์ ์ฐพ๊ธฐ๊ฐ ์ด๋ ต์ต๋๋ค.
@gaearon ๋ ํ๊ฐ์ง ํ์ด ์๋์?
์ฌ๊ธฐ์์ ๊ฒฝ๊ณ ์ ๊ด๋ จ๋ ์ ํํ ๋ผ์ธ์ ์ฐพ๊ธฐ๊ฐ ์ด๋ ต์ต๋๋ค.
๋ฌด์์ด ๊ทธ๊ฒ์ ์ด๋ ต๊ฒ ๋ง๋๋๊ฐ? ์์์ ์ธ๊ธํ๋ฏ์ด ์ค๋ฅธ์ชฝ์ "๋ฐ์"์ด๋ผ๊ณ ํ์๋์ง ์์ ์ฒซ ๋ฒ์งธ ์ค์
๋๋ค. ์ด ๊ฒฝ์ฐ Redux์ connectAdvanced
์
๋๋ค. ๊ด๋ฆฌ์๊ฐ ์ด๋ฅผ ๋ณผ ์ ์๋๋ก React Redux์ ๋ฌธ์ ๋ฅผ ์ ์ถํ์ธ์.
๋ด๊ฐ upthread์ ๋ํด ๋งํ๋ฏ์ด ์ฌ๊ธฐ์ ์ผ์ด๋๋ ๋ชจ๋ ๊ฒ์ด React-Redux์ ๋ฌธ์ ๋ผ๋ฉด _๋งค์ฐ_ ๋๋ ๊ฒ์ ๋๋ค.
์ฆ, ์ฒ์์ ์ด ๋ฉ์์ง๋ฅผ ํธ๋ฆฌ๊ฑฐํ ์์ธ์ด ์ ํํ ๋ฌด์์ธ์ง์กฐ์ฐจ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ์ค๋ฅ ๋ฉ์์ง๊ฐ ๋ฌด์์ ๋งํ๋์ง ๋ฐ์ฏค ์ดํดํ์ง๋ง ์ค์ ๋ก ์ด๋ค ์ข ๋ฅ์ ์ฑ ์ฝ๋ ํจํด์ด ํด๋น ๋์์ ์๊ฐ ๋ ๊น์?
๋๋ ์ต๊ทผ์ด์ ๋ฌ๋ ค ์์ ์ ํฌ์ฅ ๋ setState
์์ ํธ๋ค๋ฌ ํธ์ถ ์ฌ์ดํธ useEffect
๊ณผ ๊ฐ์ด : https://github.com/airbnb/lunar/commit/db08613d46ea21089ead3e7b5cfff995f15c69a7#diff (-1c3bdd397b1ce5064142488877045306R56 onChange
๋ฐ onSubmit
๋ ์ฒด์ธ ์์ชฝ์์ setState
๋ฅผ ์ฌ์ฉํฉ๋๋ค.
@martinezwilmer onPriceUpdated
๋ ์ด๋์์ ํธ์ถ๋๋์? useEffect
ํฌ์ฅํด ๋ณผ๊น์?
urql
๋ํด ๋์ผํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ๊ฒ ๊ฐ์ต๋๋ค.
์ฐ๋ฆฌ๋ ์
๋ฐ์ดํธ๋ฅผ ์กฐ์ ํ๊ธฐ ์ํด use-subscription
+ wonka(์คํธ๋ฆผ์ฉ)๋ฅผ ์ฌ์ฉํ๊ณ ์์ง๋ง ์
๋ฐ์ดํธ๋ ๋๊ธฐ์ ์ผ๋ก ์ฌ ์ ์์ต๋๋ค. ์ฌ๊ธฐ์ ์ฐ๋ฆฌ๋ ์ด๋ฏธ todos
๊ฐ์ ธ์์ผ๋ฏ๋ก Open
๋ฒํผ์ ํด๋ฆญํ๋ฉด ๊ฒฐ๊ณผ๊ฐ ์ฆ์ ํ์
๋์ด์ผ ํ์ง๋ง ์ด๊ฒ์ด ๋ค์ ์ค๋ฅ๋ฅผ ์ ๋ฐํ๋ ๊ฒ ๊ฐ์ต๋๋ค.
์ฐ๋ฆฌ์ ๊ฒฝ์ฐ ์ด๊ฒ์ด ์๋๋ ๊ฒ์ด๋ฏ๋ก ๋๊ธฐํ ๊ฒฐ๊ณผ์ ๋ํด fetching: true
๋ฅผ ํ์ํ ์ ์์ผ๋ฏ๋ก ์ธํฐํ์ด์ค๊ฐ ๋ถ์์ ํฉ๋๋ค.
์ด๊ฒ์ urql
, Apollo ์ ๊ฐ์ ํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ ์ ๋ ๋ง์ด ๋ํ๋๊ธฐ ์์ํ์ต๋๋ค.
๋๋ ์ด๊ฒ์ ๋ถ๋ช์ณค๊ณ ๋ช ์๊ฐ ๋์ ๋ฌธ์ ๊ฐ ๋ด ์ฝ๋์ ์๋ค๊ณ ๊ฐ์ ํ์ต๋๋ค. ์์ถ๋ ์คํ ์ถ์ ์ ๋ด ๊ตฌ์ฑ ์์๋ฅผ ๊ฐ๋ฆฌํค๋ฉฐ, ๋ด๊ฐ ๋ช ์์ ์ผ๋ก ์ค๋ฅ๋ฅผ _did_ ํ์ ๋ ํ์ฅ๋ ์คํ ์ถ์ ์์ ํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ณด๋ ๊ฒ์ ๋๋ฌธ ์ผ์ด ์๋๋๋ค. ์ด ํน์ ๊ฒฝ๊ณ ์ ๋ํ (์ ํ์ ์ด์ง๋ง) ์ฐ๊ตฌ์์ ๋๋ถ๋ถ์ ๊ฐ๋ฐ์๊ฐ ์ด ๋ฌธ์ ๋ฅผ ์ค์ค๋ก ์ผ์ผํค๋ ๊ฒ์ด ์๋๋ผ ๋ฐ์ํ๋ ์ฝ๋์ ์์กดํ๋ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ์ ์คํธ๋ฆผ ๋ฒ๊ทธ๊ฐ ์๋๋ผ๊ณ ๊ฐ์ ํ๋ ๊ฒ์ด ์ข์ง๋ง ์ ์คํธ๋ฆผ ๋ฒ๊ทธ์ธ ๊ฒฝ์ฐ ์ฝ๋์์ ์กด์ฌํ์ง ์๋ ๋ฌธ์ ๋ฅผ ์ถ์ ํ๋ ๋ฐ ์๊ฐ์ ๋ญ๋นํ๋ ๊ฒ์ ๋ค์ ์ค๋ง์ค๋ฝ์ต๋๋ค. ์ผ๋ฐ ์ฌ์ฉ์๊ฐ ์์ ์ด ์์ฑํ ์ฝ๋์ธ์ง, ๋ฌธ์ ๋ฅผ ์ผ์ผํจ ์ฝ๋์ ์์กดํ๋์ง ํ๋จํ ์ ์๋๋ก React๊ฐ ํ ์ ์๋ ์ผ์ด ์์ต๋๊น?
Apollo ๋ฌธ์ ์์ ๋ด๊ฐ ์ฃผ๋ชฉํ๋ ํ ๊ฐ์ง๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๊ฒฝ๊ณ ์ ์คํ ์ถ์ ์ ๋ณ๊ฒฝ ์ฌํญ์ ์ํด ๋ค์ ๋ ๋๋ง๋๋ ๊ตฌ์ฑ ์์๊ฐ ์๋๋ผ ๋ณ๊ฒฝ ์ฌํญ์ ์ด๊ธฐํํ ๊ตฌ์ฑ ์์๋ฅผ ๋ณด์ฌ์ค๋๋ค.
์ด๊ฒ์ด ๋ง๋ค๋ฉด React๊ฐ ์ฌ๊ธฐ์ ๋ ๋ง์ ์ ๋ณด๋ฅผ ์ ๊ณตํ ์ ์์ต๋๊น? ์์ ๊ตฌ์ฑ ์์์ ์ ๋ฐ์ดํธ๋ฅผ ์ ๋ฐํ ๊ตฌ์ฑ ์์๋ฅผ ๋ชจ๋ ์๋ ค์ฃผ์๊ฒ ์ต๋๊น?
@hugo ์ ๋ง์ฐฌ๊ฐ์ง๋ก ์๋ก์ด Ionic ์ ํ๋ฆฌ์ผ์ด์ ์ ํ ์คํธํ ๋ ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
npx ionic start demo sidemenu --type=react
react-scripts test
์ค์ ๋ก ์์ธ์ ์คํ ํธ๋ ์ด์ค์ ์ค๊ฐ๊ณผ ํ๋จ์ ๋ฌปํ ์์ต๋๋ค.
console.error node_modules/react-dom/cjs/react-dom.development.js:88
Warning: Cannot update a component from inside the function body of a different component.
in Route (at App.tsx:37)
in View (created by StackManagerInner)
in ViewTransitionManager (created by StackManagerInner)
in ion-router-outlet (created by IonRouterOutlet)
in IonRouterOutlet (created by ForwardRef(IonRouterOutlet))
in ForwardRef(IonRouterOutlet) (created by StackManagerInner)
in StackManagerInner (created by Context.Consumer)
in Unknown (created by Component)
in Component (created by ForwardRef(IonRouterOutlet))
in ForwardRef(IonRouterOutlet) (at App.tsx:36)
in ion-split-pane (created by IonSplitPane)
in IonSplitPane (created by ForwardRef(IonSplitPane))
in ForwardRef(IonSplitPane) (at App.tsx:34)
in NavManager (created by RouteManager)
in RouteManager (created by Context.Consumer)
in RouteManager (created by IonReactRouter)
in Router (created by BrowserRouter)
in BrowserRouter (created by IonReactRouter)
in IonReactRouter (at App.tsx:33)
in ion-app (created by IonApp)
in IonApp (created by ForwardRef(IonApp))
in ForwardRef(IonApp) (at App.tsx:32)
in App (at App.test.tsx:6)
์ด ๋ฌธ์ ๋ ์ด ๋ฌธ์ ์ ๊ด๋ จํ์ฌ ๋ด๊ฐ ์ฐพ์ ์ ์๋ ๊ฐ์ฅ ๊ฐ๊น์ด ๋ฌธ์ ์์ต๋๋ค.
https://github.com/mobxjs/mobx-react/issues/846 ์์ mobx์์ ์ด ๋ฌธ์ ๋ฅผ ์ผ์ผํค๋ ํน์ ํจํด์ ์ฐพ์์ต๋๋ค.
@sebmarkbage ๋ ์ด์ ์ด ๋ฌธ์ ๋ฅผ ์ฌํํ ์ ์์ต๋๋ค. ์ผ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ฌธ์ ๋ฅผ ์ ๋ฐ์ดํธํ์ต๋๋ค.
@jgoux ์ฐ๋ฆฌ๋ ๊ฐ์ ๋ฌธ์ ์ ์ง๋ฉดํด ์๋ ๊ฒ ๊ฐ์ต๋๋ค @Clovis ^^ Spotted
react 16.13.0
๋ํ ์
๋ฐ์ดํธ ๋ฐ์ ์ดํ์ ์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ธฐ ์์ํ์ต๋๋ค. ํน์ ์์
์ด ์๋ฃ๋ ํ ๋ด ๊ตฌ์ฑ ์์ ์ค ํ๋๊ฐ ๋ค๋ฅธ ๊ตฌ์ฑ ์์๋ฅผ ์
๋ฐ์ดํธํ๊ธฐ ๋๋ฌธ์ ๋ฌธ์ ๋ ๋งค์ฐ ๋ช
ํํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ด๊ฒ์ด ์ ๊ฒฝ๊ณ ๋ฅผ ๋์ง๋์ง ํ์คํ์ง ์์ต๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์ ์์ด ์์ต๋๊น?
@gaearon ์คํ์์ ๋๋ฒ๊น ํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์ธ๋ถ ์ ๋ณด์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค. ํด๋น ์์ ๋ฅผ ์ ๊ณตํ์ง ์์๋ค๋ฉด ๊ฐ์ธ์ ์ผ๋ก ์ด ์ค๋ฅ๊ฐ ์ด๋์์ ์๋์ง ์ ์ ์์์ ๊ฒ์ ๋๋ค. ๐
๋ด ๋ฌธ์ ๊ฐ ๊ด๋ จ๋์ด ์๋์ง ํ์คํ์ง ์์ง๋ง ๋ด ์์ ๊ตฌ์ฑ ์์์ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ๋ ค๊ณ ์๋ํ๊ณ ์์ง๋ง onChange ํธ๋ค๋ฌ๋ฅผ ์ถ๊ฐํ๋ ค๊ณ ํ ๋๋ง๋ค ์ด ์ค๋ฅ๊ฐ ๊ณ์ ๋ฐ์ํฉ๋๋ค. ๋๋ react-jsonschema-form์ ์ฌ์ฉํ๊ณ Form ๊ตฌ์ฑ ์์๋ฅผ ๊ฐ์ ธ์๊ณ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ๊ธฐ ์ํด onChange ์์ฑ์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
๋์๊ฒ ์ด๊ฒ์ ๋ฌธ์ ๋ฅผ ์ผ์ผํค๋ ํจํด์ ๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ด ์์ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ฝ์ ๋ก๊ทธ๋ ๋๋ฅผ 385ํ์ผ๋ก ๋ฐ๋ก ๊ฐ๋ฆฌ์ผฐ์ต๋๋ค.
๋๋ ์ฒ์ ๋ฐ์ํ์ง๋ง ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๊ฐ ์์ต๋๋ค.
import React, { useState } from "react";
function Home() {
const [mobileNavOpen, setMobileNavOpen] = useState(false);
return (
<div>
<button
onClick={(): void => setMobileNavOpen(true)}
type="button"
className="btn"
>
X
</button>
{mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen}/>}
</div>
);
}
function MobileNav() {
return (
<div>
<button
onClick={setMobileNavOpen(false)} //problem here
type="button"
className="btn"
>
X
</button>
</div>
);
}
export default Home;
๊ฒฐ๊ณผ: Cannot update a component from inside the function body of a different component.
๋ค์๊ณผ ๊ฐ์ด MobileNav์ setMobileNavOpen์ ํ์ดํ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
import React, { useState } from "react";
function Home() {
const [mobileNavOpen, setMobileNavOpen] = useState(false);
return (
<div>
<button
onClick={(): void => setMobileNavOpen(true)}
type="button"
className="btn"
>
X
</button>
{mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen}/>}
</div>
);
}
function MobileNav() {
return (
<div>
<button
onClick={(): void => setMobileNavOpen(false)} //fixes problem
type="button"
className="btn"
>
X
</button>
</div>
);
}
export default Home;
๊ทธ๋ฆฌ๊ณ ๊ทธ๊ฒ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค. ์ด๊ฒ์ด ๋๊ตฐ๊ฐ๋ฅผ ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค!
๋๋ ์ฒ์ ๋ฐ์ํ์ง๋ง ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๊ฐ ์์ต๋๋ค.
import React, { useState } from "react"; function Home() { const [mobileNavOpen, setMobileNavOpen] = useState(false); return ( <div> <button onClick={(): void => setMobileNavOpen(true)} type="button" className="btn" > X </button> {mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen}/>} </div> ); } function MobileNav() { return ( <div> <button onClick={setMobileNavOpen(false)} //problem here type="button" className="btn" > X </button> </div> ); } export default Home;
๊ฒฐ๊ณผ:
Cannot update a component from inside the function body of a different component.
๋ค์๊ณผ ๊ฐ์ด MobileNav์ setMobileNavOpen์ ํ์ดํ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
import React, { useState } from "react"; function Home() { const [mobileNavOpen, setMobileNavOpen] = useState(false); return ( <div> <button onClick={(): void => setMobileNavOpen(true)} type="button" className="btn" > X </button> {mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen}/>} </div> ); } function MobileNav() { return ( <div> <button onClick={(): void => setMobileNavOpen(false)} //fixes problem type="button" className="btn" > X </button> </div> ); } export default Home;
๊ทธ๋ฆฌ๊ณ ๊ทธ๊ฒ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค. ์ด๊ฒ์ด ๋๊ตฐ๊ฐ๋ฅผ ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค!
๋น์ ์ ์๋ ์ค์ ๋ก ์ฌ๋๋ค์ด react์์ ์ ์ง๋ฅด๋ ์ด๊ธฐ ์ค์ ์ค ํ๋์
๋๋ค. ์ฌ๊ธฐ์์ ๋
ผ์๋๋ ๊ฒ๊ณผ ์ ํํ ๊ฐ์ ๋ฌธ์ ์ธ์ง ํ์คํ์ง ์์ต๋๋ค. ๊ทํ์ ๋ผ์ธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. onClick={setMobileNavOpen(false)
๋ ํด๋ฆญ์ด ์๋๋ผ ๋ฒํผ์ ๋๋ฅด๋ ๋์ ํจ์๋ฅผ ํธ์ถํฉ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ํ์ดํ ํจ์๋ก ๋ํํ๋ฉด ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋ฉ๋๋ค.
<Redirect>
์ฌ์ฉ์๋ฅผ ๋ค๋ฅธ ์์น๋ก ๋ณด๋ด๊ธฐ ์ ์ Redux ์์
์ ์ ๋ฌํด์ผ ํ๋ React Router์์ ์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค. ๋ฌธ์ ๋ ๋ฐ์ก์ด ์๋ฃ๋๊ธฐ ์ ์ ๋ฆฌ๋๋ ์
์ด ๋ฐ์ํ ๊ฒ ๊ฐ์ต๋๋ค. ๋๋ ๋ด ํ๋์ ์ฝ์ํจ์ผ๋ก์จ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค.
์ ์:
<Route
render={routeProps => {
setRedirectionTarget(somePath(routeProps));
return <Redirect to={someOtherPath} />;
}}
/>;
function mapDispatchToProps(dispatch: ThunkDispatch) {
return {
setRedirectionTarget: (target: string | null) => dispatch(setRedirectionTarget(target))
};
}
export const setRedirectionTarget = (location: string | null): SetRedirectionTarget => {
return {
type: SET_REDIRECTION_TARGET,
location
};
};
ํ์:
function mapDispatchToProps(dispatch: ThunkDispatch) {
return {
setRedirectionTarget: async (target: string | null) => dispatch(await setRedirectionTarget(target))
};
}
export const setRedirectionTarget = (location: string | null): Promise<SetRedirectionTarget> => {
return Promise.resolve({
type: SET_REDIRECTION_TARGET,
location
});
};
์ค๋ฅ ๋ฉ์์ง์ ํ์ฌ ๋ ๋๋ง ์ค์ธ ๊ตฌ์ฑ ์์์ setState๊ฐ ํธ์ถ๋๋ ๊ตฌ์ฑ ์์ ๋ชจ๋์ ๋ํ ์ด๋ฆ์ด ํฌํจ๋๋๋ก ๋ง๋ค ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ๋๊ตฌ๋ ์ง ์ด๊ฒ์ ์ํด PR์ ๋ณด๋ด๊ณ ์ถ์ต๋๊น?
์ค๋ฅ ๋ฉ์์ง์ ํ์ฌ ๋ ๋๋ง ์ค์ธ ๊ตฌ์ฑ ์์์ setState๊ฐ ํธ์ถ๋๋ ๊ตฌ์ฑ ์์ ๋ชจ๋์ ๋ํ ์ด๋ฆ์ด ํฌํจ๋๋๋ก ๋ง๋ค ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ๋๊ตฌ๋ ์ง ์ด๊ฒ์ ์ํด PR์ ๋ณด๋ด๊ณ ์ถ์ต๋๊น?
์ด ๋ถ๋ถ์ ์ดํด๋ณด๊ฒ ๋์ด ๊ธฐ์ฉ๋๋ค. ๋ด๊ฐ ์์์ผ ํ ํฌ์ธํฐ๊ฐ ์์ต๋๊น?
@samcooke98 ์ด PR์ ์ด์์ต๋๋ค https://github.com/facebook/react/pull/18316
๋ค๋ฅธ ์ฌ๋๋ค์ด ์ง์ ํ๋ฏ์ด Apollo์ ๊ฐ์ ํํฌ์ ๊ตฌ๋
์ด ์๊ณ ๋ฐ์ดํฐ ์์ ์ ์ ์ฅ์๋ฅผ ์
๋ฐ์ดํธํ๋ ค๊ณ ์๋ํ๋ ๊ฒฝ์ฐ ์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ๊ฐ๋จํ ์์ ์ useEffect
์
export const useOrderbookSubscription = marketId => {
const { data, error, loading } = useSubscription(ORDERBOOK_SUBSCRIPTION, {
variables: {
marketId,
},
})
const formattedData = useMemo(() => {
// Don't dispatch in here.
}, [data])
// Don't dispatch here either
// Dispatch in a useEffect
useEffect(() => {
orderbookStore.dispatch(setOrderbookData(formattedData))
}, [formattedData])
return { data: formattedData, error, loading }
}
Hyper ์์ ์ด ๋ฌธ์ ์ ์ง๋ฉดํ์ง๋ง ํํฌ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์์ผ๋ฉฐ ํธ์ถ ์คํ์ ๋ ๋๋ง ํธ์ถ์์ ์๋ฌด ๊ฒ๋ ์ฐพ์ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์คํ์ UNSAFE_componentWillReceiveProps
ํธ์ถ์ด ์์์ต๋๋ค. componentDidUpdate
์
๋ฐ์ดํธํ๋ฉด ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์์ต๋๋ค. https://github.com/zeit/hyper/pull/4382
๋๊ตฐ๊ฐ์๊ฒ ๋์์ด ๋ ์ ์์ผ๋ฉด ์ฌ๊ธฐ์ ๊ฒ์ํ์ญ์์ค.
์ฌ๊ธฐ์์๋ ๋ง์ฐฌ๊ฐ์ง๋ก UNSAFE_componentWillMount ํธ์ถ์ด ์์๊ณ ์ด๋ฅผ ๋ณ๊ฒฝ/์ ๊ฑฐํ๋ฉด ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์์ต๋๋ค.
๊ทธ๋ฌ๋ ์ฐ๋ฆฌ๋ ํํฌ๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉฐ ํธ์ถ ์คํ์ ๋ ๋๋ง ํธ์ถ์์ ์๋ฌด ๊ฒ๋ ์ฐพ์ ์ ์์ต๋๋ค.
์ด์ํ๊ฒ ๋ค๋ฆฝ๋๋ค. ๋๋ ๋น์ ์ด ์ด๋ป๊ฒ ์ด ๊ฒฝ๊ณ ๋ฅผ ๋ฐ๋์ง ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. setState๊ฐ ํจ์ ๊ตฌ์ฑ ์์์ ์ํ๋ ๊ฒฝ์ฐ์๋ง ๋ฐ์ํฉ๋๋ค. ๋น์ ์ ์คํ์ ์ด๋ป์ต๋๊น?
๊ทธ๋ฌ๋ ์ฐ๋ฆฌ๋ ํํฌ๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉฐ ํธ์ถ ์คํ์ ๋ ๋๋ง ํธ์ถ์์ ์๋ฌด ๊ฒ๋ ์ฐพ์ ์ ์์ต๋๋ค.
์ด์ํ๊ฒ ๋ค๋ฆฝ๋๋ค. ๋๋ ๋น์ ์ด ์ด๋ป๊ฒ ์ด ๊ฒฝ๊ณ ๋ฅผ ๋ฐ๋์ง ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. setState๊ฐ ํจ์ ๊ตฌ์ฑ ์์์ ์ํ๋ ๊ฒฝ์ฐ์๋ง ๋ฐ์ํฉ๋๋ค. ๋น์ ์ ์คํ์ ์ด๋ป์ต๋๊น?
Redux๋ก ๊ตฌ์ฑ ์์๋ฅผ ๋ถ๋ฅํ๊ณ ๊ตฌ์ฑ ์์์ ํ๋ฌ๊ทธ์ธ์ ์ ์ฉํ๋ ๊ธฐ๋ฅ. ์๋ง๋ ๊ทธ๊ฒ์ด ๊ธฐ๋ฅ ๊ตฌ์ฑ ์์๋ก ๊ฐ์ฃผ๋๋ ์ด์ ์ผ ๊ฒ์ ๋๋ค. ๊ทธ๋ฐ๋ฐ ์ ์๋ช ์ฃผ๊ธฐ ํํฌ๋ฅผ ์ ๋ฐ์ดํธํ๋ฉด ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋ฉ๋๊น?
์ ๋ชจ๋ฅด๊ฒ ์ด. ์๋๋ฐ์ค์์ ๊ฒฉ๋ฆฌ๋ ์์ ๋ฅผ ๋ง๋ค ์ ์์ต๋๊น? ๋น์ ์ด ์์์น ๋ชปํ ๋ค๋ฅธ ์ผ์ ํ๊ณ ์์์ง๋ ๋ชจ๋ฅธ๋ค๋ ์๊ฐ์ด ๋ญ๋๋ค.
๊ฒฉ๋ฆฌ๋ ์์์ ๋ณต์ ํ ์ ์๋์ง ํ์คํ์ง ์์ต๋๋ค. ์์ธ์ ์ฐพ๋ ๋ฐ ์ด๋ ค์์ ๊ฒช์๊ณ ์คํ ์ถ์ ์ ์๊ณ ์
๋ฐ์ดํธ ๋๊ธฐ ์ค์ด์๋ ๊ฒ์ฒ๋ผ ์๋ช
์ฃผ๊ธฐ ํํฌ๋ฅผ ๋ฐฉ๊ธ ์
๋ฐ์ดํธํ์ต๋๋ค. ๊ทธ๊ฒ์ ์ด๋ป๊ฒ ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค.
์ฌ๊ธฐ ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์์ ์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ๋ณผ ์ ์์ต๋๋ค.
๊ทธ ๋น์ UNSAFE_componentWillReceiveProps
์ componentDidUpdate
๊ฐ ๋ชจ๋ ๊ตฌ์ฑ ์์์ ์์๊ธฐ ๋๋ฌธ์ผ ์ ์์ต๋๊น(์์ ํ์ง ์์ ๊ฒ์ด ์ค์๋ก ๊ฑฐ๊ธฐ์ ๋จ์ ์์)?
๋ํ ์ด ๊ฒฝ๊ณ ๊ฐ ํ์๋๋ฉฐ ์คํ ์ถ์ ์ setScriptLoaded
ํํฌ๋ฅผ ๊ฐ๋ฆฌํต๋๋ค(๋ด ์ฌ์ฉ์ ์ง์ ํํฌ๋ ์๋ ์ฐธ์กฐ). ๋ฐ๋ผ์ useEffect
์ฌ์ฉํ๋๋ผ๋ setState
ํธ๋ค๋ฌ๊ฐ ๋ค๋ฅธ ๋น๋๊ธฐ ์ฝ๋ฐฑ ๋ด์ ์ค์ฒฉ๋๋ฉด React๋ ์ฌ์ ํ ๊ฒฝ๊ณ ๋ฅผ ๋์ง ๊ฒ์
๋๋ค(์ ๊ฒฝ์ฐ์๋ setTimeout
๋ฐ load
์ด๋ฒคํธ ํธ๋ค๋ฌ)? Hooks๋ฅผ ์ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ฏ๋ก ์กฐ์ธ์ ์ฃผ์๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค. ๊ฐ์ฌํฉ๋๋ค!
/**
* Detect when 3rd party script is ready to use
*
* <strong i="11">@param</strong> {function} verifyScriptLoaded Callback to verify if script loaded correctly
* <strong i="12">@param</strong> {string} scriptTagId
*/
export const useScriptLoadStatus = (verifyScriptLoaded, scriptTagId) => {
let initLoadStatus = true; // HTML already includes script tag when rendered server-side
if (__BROWSER__) {
initLoadStatus = typeof verifyScriptLoaded === 'function' ? verifyScriptLoaded() : false;
}
const [isScriptLoaded, setScriptLoaded] = useState(initLoadStatus);
useEffect(() => {
if (!isScriptLoaded) {
// need to wrap in setTimeout because Helmet appends the script tags async-ly after component mounts (https://github.com/nfl/react-helmet/issues/146)
setTimeout(() => {
let newScriptTag = document.querySelector(`#${scriptTagId}`);
if (newScriptTag && typeof verifyScriptLoaded === 'function') {
newScriptTag.addEventListener('load', () => {
return verifyScriptLoaded() ? setScriptLoaded(true) : null;
});
// double check if script is already loaded before the event listener is added
return verifyScriptLoaded() ? setScriptLoaded(true) : null;
}
}, 100);
}
});
return isScriptLoaded;
};
@LabhanshAgrawal
๊ทธ ๋น์ UNSAFE_componentWillReceiveProps์ componentDidUpdate๊ฐ ๋ชจ๋ ๊ตฌ์ฑ ์์์ ์์๊ธฐ ๋๋ฌธ์ผ ์ ์์ต๋๊น(์์ ํ์ง ์์ ํญ๋ชฉ์ด ์ค์๋ก ๊ฑฐ๊ธฐ์ ๋จ์ ์์)?
๋ผ์ดํ ์ฌ์ดํด ๋ฐฉ๋ฒ์ด ์ฌ๊ธฐ์ ์ ํ ๊ด๋ จ์ด ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ด๊ฒ์ด ๋ด๊ฐ ๋น์ ์ ์์์ ๋ญ๊ฐ ์ด์ํ๋ค๊ณ ๋งํ๋ ์ด์ ์ ๋๋ค.
@suhanw CodeSandbox ์์ ์์ ํ ์์ ๋ฅผ ์ ๊ณตํ์ญ์์ค. ์ด ๊ฒฝ๊ณ ๋ฅผ ์ ๋ฐํด์ผ ํ๋ ์ฝ๋์๋ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
@LabhanshAgrawal ์ ์ฒด ์คํ์ ๊ฒ์ํ ์ ์์ต๋๊น? ๋๋ UNSAFE_componentWillReceiveProps
(๋ ๋๋ง๊ณผ ๋์ผ)๊ฐ ๋ค๋ฅธ ๊ตฌ์ฑ ์์์์ setState
๋ฅผ ํธ์ถํ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
backend.js:6 Warning: Cannot update a component from inside the function body of a different component.
in Term (created by _exposeDecorated(Term))
in _exposeDecorated(Term) (created by DecoratedComponent)
in DecoratedComponent (created by TermGroup_)
in TermGroup_ (created by ConnectFunction)
in ConnectFunction (created by Connect(TermGroup_))
in Connect(TermGroup_) (created by _exposeDecorated(TermGroup))
in _exposeDecorated(TermGroup) (created by DecoratedComponent)
in DecoratedComponent (created by Terms)
in div (created by Terms)
in div (created by Terms)
in Terms (created by _exposeDecorated(Terms))
in _exposeDecorated(Terms) (created by DecoratedComponent)
in DecoratedComponent (created by ConnectFunction)
in ConnectFunction (created by Connect(DecoratedComponent))
in Connect(DecoratedComponent) (created by Hyper)
in div (created by Hyper)
in div (created by Hyper)
in Hyper (created by _exposeDecorated(Hyper))
in _exposeDecorated(Hyper) (created by DecoratedComponent)
in DecoratedComponent (created by ConnectFunction)
in ConnectFunction (created by Connect(DecoratedComponent))
in Connect(DecoratedComponent)
in Provider
r @ backend.js:6
printWarning @ react-dom.development.js:88
error @ react-dom.development.js:60
warnAboutRenderPhaseUpdatesInDEV @ react-dom.development.js:23260
scheduleUpdateOnFiber @ react-dom.development.js:21196
dispatchAction @ react-dom.development.js:15682
checkForUpdates @ connectAdvanced.js:88
handleChangeWrapper @ Subscription.js:97
(anonymous) @ Subscription.js:23
batchedUpdates$1 @ react-dom.development.js:21887
notify @ Subscription.js:19
notifyNestedSubs @ Subscription.js:92
checkForUpdates @ connectAdvanced.js:77
handleChangeWrapper @ Subscription.js:97
(anonymous) @ Subscription.js:23
batchedUpdates$1 @ react-dom.development.js:21887
notify @ Subscription.js:19
notifyNestedSubs @ Subscription.js:92
handleChangeWrapper @ Subscription.js:97
dispatch @ redux.js:222
e @ VM64:1
(anonymous) @ effects.ts:11
(anonymous) @ write-middleware.ts:14
(anonymous) @ index.js:11
(anonymous) @ plugins.ts:538
(anonymous) @ plugins.ts:540
(anonymous) @ index.js:11
dispatch @ redux.js:638
(anonymous) @ sessions.ts:124
(anonymous) @ index.js:8
dispatch @ VM64:1
onResize @ terms.ts:62
(anonymous) @ term.js:179
e.fire @ xterm.js:1
t.resize @ xterm.js:1
e.resize @ xterm.js:1
e.fit @ xterm-addon-fit.js:1
fitResize @ term.js:291
UNSAFE_componentWillReceiveProps @ term.js:408
callComponentWillReceiveProps @ react-dom.development.js:12998
updateClassInstance @ react-dom.development.js:13200
updateClassComponent @ react-dom.development.js:17131
beginWork @ react-dom.development.js:18653
beginWork$1 @ react-dom.development.js:23210
performUnitOfWork @ react-dom.development.js:22185
workLoopSync @ react-dom.development.js:22161
performSyncWorkOnRoot @ react-dom.development.js:21787
(anonymous) @ react-dom.development.js:11111
unstable_runWithPriority @ scheduler.development.js:653
runWithPriority$1 @ react-dom.development.js:11061
flushSyncCallbackQueueImpl @ react-dom.development.js:11106
flushSyncCallbackQueue @ react-dom.development.js:11094
batchedUpdates$1 @ react-dom.development.js:21893
notify @ Subscription.js:19
notifyNestedSubs @ Subscription.js:92
handleChangeWrapper @ Subscription.js:97
dispatch @ redux.js:222
e @ VM64:1
(anonymous) @ effects.ts:11
(anonymous) @ write-middleware.ts:14
(anonymous) @ index.js:11
(anonymous) @ plugins.ts:538
(anonymous) @ plugins.ts:540
(anonymous) @ index.js:11
dispatch @ redux.js:638
effect @ ui.ts:60
(anonymous) @ effects.ts:13
(anonymous) @ write-middleware.ts:14
(anonymous) @ index.js:11
(anonymous) @ plugins.ts:538
(anonymous) @ plugins.ts:540
(anonymous) @ index.js:11
dispatch @ redux.js:638
(anonymous) @ ui.ts:54
(anonymous) @ index.js:8
dispatch @ VM64:1
(anonymous) @ index.tsx:162
emit @ events.js:210
(anonymous) @ rpc.ts:31
emit @ events.js:210
onMessage @ init.ts:50
@gaearon ๋น ๋ฅธ ๋ต๋ณ ๊ฐ์ฌํฉ๋๋ค. CodeSandbox์์ ์์ ๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์์๋ผ ๊ฒ์ ๋๋ค(์ด๋ ค์). ํ์ง๋ง ๊ทธ ๋์์ ์ด๊ฒ์ด ์ ์ ์ฒด ์คํ ์ถ์ ์ ๋๋ค.
๋ด ์ฌ์ฉ์ ์ ์ ํํฌ๋ฅผ ๊ฐ๋ฆฌํค๋ ์ค์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. https://gist.github.com/suhanw/bcc2688bba131df8301dae073977654f#file -stack-trace-L144
๋ด ์ฌ์ฉ์ ์ง์ ํํฌ ์ ํ์ ์คํ ์ถ์ ์ ๋ ์กฐ์ฌํด์ผ ํ ๊ฒ์ด ์๋์ง ์ดํด๋ณด๊ณ ์๋ ค์ฃผ๋ฉด ์ ๋ง ์ข์ ๊ฒ์ ๋๋ค. ๊ฐ์ฌ ํด์!
@LabhanshAgrawal ์คํ์์ UNSAFE_componentWillReceiveProps
๋ Redux ์์
์ ์ ๋ฌํ๋ fitResize
๋ฅผ ํธ์ถํ๊ณ ์ด๋ ์ฐจ๋ก๋ก ๋ง์ ๊ตฌ์ฑ ์์๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค. ๋ฐ๋ผ์ ๋ฌธ์ . ์, componentDidUpdate
๋ณ๊ฒฝํ๋ฉด ์๋ํฉ๋๋ค.
@suhanw ์คํ์์ ModuleImpressionTracker
๋ผ๋ ๊ฒ์ด ์์ฑ์ ๋์ Redux ์์
์ ์ ๋ฌํ๋ ๊ฒ์ผ๋ก ๋ํ๋ฉ๋๋ค. ์์ฑ์๋ ๋ถ์์ฉ์ด ์์ด์ผ ํฉ๋๋ค. ๋๋ ๊ทธ๊ฒ์ด ๋น์ ์ Hook์ด ์๋๋ผ ๋ฌธ์ ์ ์์ธ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์๊ฒ ์ต๋๋ค. UNSAFE_componentWillReceiveProps
๋ ๋ ๋๋ง์ผ๋ก ๊ณ์ฐ๋์ง๋ง componentDidUpdate
๋ ๊ณ์ฐ๋์ง ์์ต๋๋ค.
setState๋ฅผ ์ํํ๋ ๊ธฐ๋ฅ ๊ตฌ์ฑ ์์ ๋ฐ ํํฌ์ ๋ฌธ์ ์ธ ์ ์ ์์ ๋
ผ์์์ ๋ช
ํํ๊ฒ ํ์
ํ ์ ์๋ค๋ ์ ์ ์กฐ๊ธ ๋ช
ํํ ํด์ฃผ์ค ์ ์์ต๋๊น?
์ง๋ฌธ์ด ์ฝ๊ฐ ์ด๋ฆฌ์๊ฑฐ๋ ์ ํ
์ดํฌ ์์์ด ์๋ชป๋ ๊ฒฝ์ฐ ์ฌ๊ณผ๋๋ฆฝ๋๋ค. ์ ๋ ์ด๊ฒ์ ์ฝ๊ฐ ์ต์ํฉ๋๋ค.
@LabhanshAgrawal
setState๋ฅผ ์ํํ๋ ๊ธฐ๋ฅ ๊ตฌ์ฑ ์์ ๋ฐ ํํฌ์ ๋ฌธ์ ์ธ ์ ์ ์์ ๋ ผ์์์ ๋ช ํํ๊ฒ ํ์ ํ ์ ์๋ค๋ ์ ์ ์กฐ๊ธ ๋ช ํํ ํด์ฃผ์ค ์ ์์ต๋๊น?
์์งํ ๋๋ ์ค๊ฐ์ ์๋ ๋ชจ๋ Redux ๊ฒ๋ค ๋๋ฌธ์ ๋ ์์ ์ ํ์ ํ์ง ๋ชปํ๋ค. React Redux๊ฐ ๊ตฌํ๋๋ ๋ฐฉ์ ๋๋ฌธ์ ๊ฝค ํผ๋์ค๋ฝ์ต๋๋ค. ๋๊ตฐ๊ฐ๊ฐ React ๋จ๋ ์ผ๋ก ๊ด๋ จ๋์ง๋ง ํด๋์ค ๊ตฌ์ฑ ์์๋ฅผ ์ฌ์ฉํ๋ ๋ช ํํ ์ฌํ์ ์ป์ ์ ์๋ค๋ฉด ์ข์ ๊ฒ์ ๋๋ค.
์ฌ์ ํ ๋ง์ ์คํ ์ถ์ ์ด ๋ถ์ฌ๋ฃ์ด์ง๊ณ ์ ํ์ ๊ด๊ณ์์ด ์ค์ ๋ฌธ์ ์ ๋ํ ์ค์ ์ฌํ์ด ๋ง์ง ์์ ๊ฒ ๊ฐ์ต๋๋ค.
urql
๊ฒ์ @gaearon์ ์๋ํ
<Todos />
๋ง์ดํธ๊ฐ ์์ต๋๋ค.urqlClient
์ฐ๊ฒฐ๋ ์คํธ๋ฆผ์ ์ค์ ํ์ต๋๋ค.<Todos />
๋ ๋๋งํ๋ฉด ๋์ผํ ์ฟผ๋ฆฌ + ๋ณ์ ์กฐํฉ์ด ์์ฑ๋๋ฏ๋ก ์ฒซ ๋ฒ์งธ ๋จ๊ณ์ <Todos />
์ ๋ํ ๊ฒฐ๊ณผ๊ฐ ์๋ก ๊ณ ์ณ์ง๋๋ค.use-subscription
๋ ๋ ๋ค์ ๋ํด ํธ๋ฆฌ๊ฑฐ๋ฉ๋๋ค.์ฌํ - ์ฒซ ๋ฒ์งธ ์ฟผ๋ฆฌ๊ฐ ๋ ๋๋ง๋ ๋ ์๋จ์์ "์ด๊ธฐ"๋ฅผ ๋๋ฆ ๋๋ค.
์
๋ฐ์ดํธ๋ฅผ ๋๊ธฐ์ด์ ๋ฃ์ ์๋ ์์ง๋ง top-down
์ปจํ
์คํธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ ๋๋งํ์ง ์๋ ํ ์ด ๋ฌธ์ ๋ฅผ ์ฐํํ ์ ์๋ค๊ณ ๊ฐ์ ํฉ๋๊น? ์ด๋ก ์ ์ผ๋ก ์ด๊ฒ์ ์ด ๊ฒฝ์ฐ์ ์๋๋ ๋์์
๋๋ค. Relay๊ฐ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ด ๊ถ๊ธํฉ๋๋ค.
ํธ์ง: use-subscription
์ getCurrentValue
๋์ ๋ชจ๋ ๊ตฌ๋
์๊ฐ ์
๋ฐ์ดํธํ๋๋ก ํธ๋ฆฌ๊ฑฐํ์ง ์์์ผ๋ก์จ urql์ ๊ฒฝ์ฐ์ ๋ํ ์๋ฃจ์
์ ์ฐพ์์ ์ ์์ต๋๋ค.
https://github.com/FormidableLabs/urql/commit/3a597dd92587ef852c18139e9781e853f763e930
์, ๋ ์์ธํ ์ดํด๋ณด๋ฉด ์๋ ์๋ํ๋ ๊ฒ๋ณด๋ค ๋ ๋ง์ ๊ฒฝ์ฐ(์: ํด๋์ค์ ๊ฒฝ์ฐ)์์ ๊ฒฝ๊ณ ํ๊ณ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ฐ๋ฆฌ๋ ๊ทธ ์ค ์ผ๋ถ๋ฅผ ์นจ๋ฌต์ํฌ ๊ฒ์ ๋๋ค.
@JoviDeCroock ์ด ์์ ๋ urql
๊ฐ ๋ฌด์์ ํ๋์ง ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์ ๋ณ๋ก ๋์์ด ๋์ง ์์ต๋๋ค. :-) ํจํด์ ๋ํ ํผ๋๋ฐฑ์ ์ํ์ ๋ค๋ฉด ํด๋น ํจํด์ ๊ฐ๋ณ์ ์ผ๋ก ๋ณด์ฌ์ฃผ๋ ์๋๋ฐ์ค๋ฅผ ์ค๋นํ ์ ์์ต๋๊น?
@JoviDeCroock ์, getCurrentValue
๋ ํ์คํ ๋ถ์์ฉ์ด ์์ต๋๋ค . ์ฐ๋ฆฌ๋ ๊ทธ ์ด๋ฆ์ด ๊ทธ๊ฒ์ ๋ํด ๊ฝค ๋ช
์์ ์ด๋ผ๊ณ ์๊ฐํ์ต๋๋ค.
์ฌ์ฉ์ ์ง์ ํํฌ์ ๋ฃจํธ ๋ฒ์ ๋ด์์ redux ์์ ์ ๋์คํจ์นํ ๋ ์ด ๊ฒฝ๊ณ ๊ฐ ํ์๋๋ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค.
function useCustomHook() {
const dispatch = useDispatch()
const value = useSomeOtherHook()
dispatch(action(value))
}
useEffect
๋์คํจ์น๋ฅผ โโ๋ํํ์ฌ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค.
@Glinkis ์๊ด์์ด ๋์ ํจํด์ฒ๋ผ ๋ค๋ฆฝ๋๋ค. ๊ตฌ์ฑ ์์๊ฐ ๋ ๋๋ง๋ ๋๋ง๋ค ์ ์ฒด ํธ๋ฆฌ์ ์๋ฆฌ๊ณ ์ถ์ ์ด์ ๋ ๋ฌด์์ ๋๊น?
@gaearon ๋ค, ์ฐ๋ฆฌ๊ฐ ํด๊ฒฐํ๋ ค๊ณ ํ๋ ๋ฌธ์ ๋ ์ฌ๊ธฐ์ ๋ ์ ์ค๋ช ๋์ด ์๊ณ ๊ฝค ํํ ๊ฒ ๊ฐ์ต๋๋ค.
@Glinkis ์๊ด์์ด ๋์ ํจํด์ฒ๋ผ ๋ค๋ฆฝ๋๋ค. ๊ตฌ์ฑ ์์๊ฐ ๋ ๋๋ง๋ ๋๋ง๋ค ์ ์ฒด ํธ๋ฆฌ์ ์๋ฆฌ๊ณ ์ถ์ ์ด์ ๋ ๋ฌด์์ ๋๊น?
๋ด redux ์ํ๋ฅผ ๋ด ๊ฒฝ๋ก์ ID์ ๋๊ธฐํ๋ ์ํ๋ก ์ ์งํด์ผ ํ๋ฏ๋ก ๊ฒฝ๋ก๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์ด ์ ๋ฐ์ดํธ๋ฅผ ์ ๋ฌํฉ๋๋ค.
์ด๊ฒ์ด ์ฐจ์ ์ฑ ์ผ ์ ์๋ค๋ ๊ฒ์ ์๊ณ ์์ง๋ง ์ ํ๊ธฐ ๋ด๋ถ์ ๋ผ์ฐํ ๋ฐ์ดํฐ์ ์ก์ธ์คํ ์ ์๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฐพ์ง ๋ชปํ์ต๋๋ค.
@Glinkis ๊ฒฝ๋ก ๋ฐ์ดํฐ๋ ์ด๋์์
@JoviDeCroock ์ด ํจํด์ ๋ํ ์ต์ ๊ถ์ฅ ์ฌํญ์ ์ฌ์ฉ์ ์ง์ ์์ฝ ๊ฐ๋น์ง ์์ง ํจ์ค๋ผ๊ณ ์๊ฐํฉ๋๋ค.
@Glinkis ๊ฒฝ๋ก ๋ฐ์ดํฐ๋ ์ด๋์์
์ด๊ฒ์ด ๋ด๊ฐ ์ด ํ ๋ก ์ ์ํ๋์ง ํ์คํ์ง ์์ง๋ง ์ด๊ฒ์ ๋ด ํํฌ์ ๋๋ค.
export function useOpenFolder() {
const dispatch = useDispatch()
const match = useRouteMatch('/:workspace/(super|settings)?/:type?/:id?/(item)?/:item?')
const { id, item } = match?.params || {}
useEffect(() => {
dispatch(
openFolder({
id: id || '',
item: item || '',
})
)
}, [dispatch, item, id])
}
๋์ค์ ๋ค์๊ณผ ๊ฐ์ ์ ํ๊ธฐ์ ์ด ์ํ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
export const getActiveItem = createSelector(
[getActiveFolderItem, getItems],
(activeItem, items) => items.all[activeItem]
)
@Glinkis ์, ์ฌ๊ธฐ์์ ๋ง๋ฌด๋ฆฌํ๊ฒ ์ต๋๋ค. ํ์ง๋ง ์ ์ ์์ ์์ ๊ตฌ์ฑ ์์์์ useRouteMatch
๋ฅผ ์ฝ๊ณ ID๋ฅผ ์ํ์ผ๋ก ์ ๋ฌํ ๋ค์ ํ์์ฒ๋ผ ์ ํ๊ธฐ์์ ์ํ์ ์ฝ๋ ๊ฒ์
๋๋ค. (์ฌ์ค ์ด๊ฒ์ด ์์ฆ Redux์์ ์ด๋ป๊ฒ ์ํ๋๋์ง ๋ชจ๋ฅด์ง๋ง ์ด๋ค ๋ฐฉ๋ฒ์ด ์์ ๊ฒ์
๋๋ค.)
์๊ฒ ์ต๋๋ค.
UNSAFE_componentWillReceiveProps
๋ ๋ ๋๋ง์ผ๋ก ๊ณ์ฐ๋์ง๋งcomponentDidUpdate
๋ ๊ณ์ฐ๋์ง ์์ต๋๋ค.
@LabhanshAgrawal ๋ง์ต๋๋ค. ์ฌ๊ธฐ์ ๋ช ๊ฐ์ง ๋ฐฐ๊ฒฝ ์ค๋ช :
๊ฐ๋ ์ ์ผ๋ก React๋ ๋ ๋จ๊ณ๋ก ์๋ํฉ๋๋ค.
- ๋ ๋๋ง ๋จ๊ณ๋ ์๋ฅผ ๋ค์ด DOM์ ์ด๋ค ๋ณ๊ฒฝ์ด ํ์ํ์ง ๊ฒฐ์ ํฉ๋๋ค. ์ด ๋จ๊ณ์์ React๋
render
ํธ์ถํ ๋ค์ ๊ฒฐ๊ณผ๋ฅผ ์ด์ ๋ ๋๋ง๊ณผ ๋น๊ตํฉ๋๋ค.- ์ปค๋ฐ ๋จ๊ณ๋ React๊ฐ ๋ณ๊ฒฝ ์ฌํญ์ ์ ์ฉํ๋ ๋จ๊ณ์ ๋๋ค. (React DOM์ ๊ฒฝ์ฐ React๊ฐ DOM ๋ ธ๋๋ฅผ ์ฝ์ , ์ ๋ฐ์ดํธ ๋ฐ ์ ๊ฑฐํ ๋์ ๋๋ค.) React๋ ์ด ๋จ๊ณ์์
componentDidMount
๋ฐcomponentDidUpdate
์ ๊ฐ์ ์๋ช ์ฃผ๊ธฐ๋ ํธ์ถํฉ๋๋ค.์ปค๋ฐ ๋จ๊ณ๋ ์ผ๋ฐ์ ์ผ๋ก ๋งค์ฐ ๋น ๋ฅด์ง๋ง ๋ ๋๋ง์ด ๋๋ฆด ์ ์์ต๋๋ค. ์ด๋ฌํ ์ด์ ๋ก ์์ ๋ ๋์ ๋ชจ๋(์์ง ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ฑํ๋์ด ์์ง ์์)๋ ๋ ๋๋ง ์์ ์ ์กฐ๊ฐ์ผ๋ก ๋๋๊ณ ๋ธ๋ผ์ฐ์ ์ฐจ๋จ์ ํผํ๊ธฐ ์ํด ์์ ์ ์ผ์ ์ค์งํ๋ค๊ฐ ๋ค์ ์์ํฉ๋๋ค. ์ด๊ฒ์ React๊ฐ ์ปค๋ฐํ๊ธฐ ์ ์ ๋ ๋๋ง ๋จ๊ณ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๋ ๋ฒ ์ด์ ํธ์ถํ๊ฑฐ๋ ์ปค๋ฐํ์ง ์๊ณ ํธ์ถํ ์ ์์์ ์๋ฏธํฉ๋๋ค(์ค๋ฅ ๋๋ ๋ ๋์ ์ฐ์ ์์ ์ค๋จ์ผ๋ก ์ธํด).
๋ ๋๋ง ๋จ๊ณ ์๋ช ์ฃผ๊ธฐ์๋ ๋ค์๊ณผ ๊ฐ์ ํด๋์ค ๊ตฌ์ฑ ์์ ๋ฉ์๋๊ฐ ํฌํจ๋ฉ๋๋ค.
constructor
componentWillMount
(๋๋UNSAFE_componentWillMount
)componentWillReceiveProps
(๋๋UNSAFE_componentWillReceiveProps
)componentWillUpdate
(๋๋UNSAFE_componentWillUpdate
)getDerivedStateFromProps
shouldComponentUpdate
render
setState
์ ๋ฐ์ดํฐ ํจ์(์ฒซ ๋ฒ์งธ ์ธ์)์์ ๋ฉ์๋๋ ๋ ๋ฒ ์ด์ ํธ์ถ๋ ์ ์์ผ๋ฏ๋ก ๋ถ์์ฉ์ด ํฌํจ๋์ง ์๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ด ๊ท์น์ ๋ฌด์ํ๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐ ์๋ชป๋ ์์ฉ ํ๋ก๊ทธ๋จ ์ํ๋ฅผ ๋น๋กฏํ ๋ค์ํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ๋ถํํ๋ ์ด๋ฌํ ๋ฌธ์ ๋ ์ข ์ข ๋น๊ฒฐ์ ์ ์ผ ์ ์์ผ๋ฏ๋ก ๊ฐ์งํ๊ธฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค.
์, ๋ ์์ธํ ์ดํด๋ณด๋ฉด ์๋ ์๋ํ๋ ๊ฒ๋ณด๋ค ๋ ๋ง์ ๊ฒฝ์ฐ(์: ํด๋์ค์ ๊ฒฝ์ฐ)์์ ๊ฒฝ๊ณ ํ๊ณ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ฐ๋ฆฌ๋ ๊ทธ ์ค ์ผ๋ถ๋ฅผ ์นจ๋ฌต์ํฌ ๊ฒ์ ๋๋ค.
์๋ํ ๊ฒ ์ด์์ด๋ผ ํ ์ง๋ผ๋ ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ก์ ํธ๋ฅผ ๊ฐ์ ํ๋ ๋ฐ ๋์์ด ๋๊ธฐ ๋๋ฌธ์ ๊ฐ์ง๊ณ ์๋ ๊ฒ์ด ์ข๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ด ์์ฒด ์ค๋ช ์ค๋ฅ ๋ฉ์์ง "๋ค๋ฅธ ๊ตฌ์ฑ ์์์ ํจ์ ๋ณธ๋ฌธ ๋ด๋ถ์์ ๊ตฌ์ฑ ์์๋ฅผ ์ ๋ฐ์ดํธํ ์ ์์ต๋๋ค"
์ฆ, ์ปดํฌ๋ํธ๋ฅผ ํธ์ถํ๋ ๋์ ํจ์๋ก ์คํํฉ๋๋ค.
๋ค์๊ณผ ๊ฐ์ ์:
const App = () => {
const fetchRecords = () => {
return <div>Loading..</div>;
};
return fetchRecords() // and not like <FetchRecords /> unless it is functional component.
};
export default App;
@rpateld ๋๋ ๋น์ ์ด ๋ณด์ฌ์ฃผ๋ ์๊ฐ ์ด ๊ฒฝ๊ณ ์ ๊ด๋ จ์ด ์๋ค๊ณ ์๊ฐํ์ง ์์ต๋๋ค.
https://github.com/facebook/react/pull/18330 ์ ์ฐ๋ฆฌ๊ฐ ๋ฐ์ฌ๋ฅผ ์์ํ ์๋๊ฐ ์์๋ ๊ฒฝ์ฐ๋ฅผ ํด๊ฒฐํ ๊ฒ์ ๋๋ค.
๋๋ ๋ํ react@experimental
+ react-redux
+ redux
์ด ๋ฌธ์ ์ ์ง๋ฉดํ๊ณ ์์ต๋๋ค.
์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
import React, { Suspense } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { Redirect } from 'react-router-dom'
import PropTypes from 'prop-types'
import { userActions, cabinetActions, tokensActions } from '../../actions'
import { CircularProgress } from '@material-ui/core'
import { api } from './api'
const Cabinet = ({ resource }) => {
resource.read()
return <h1>cabinet</h1>
}
Cabinet.propTypes = {
resource: PropTypes.shape({
read: PropTypes.func
})
}
const CabinetPage = ({
failedToLoad,
tokensRefreshFailed,
logout,
loadCabinet,
clearTokens,
clearCabinet
}) => {
if (tokensRefreshFailed || failedToLoad) {
clearTokens()
clearCabinet()
logout()
return <Redirect to='/login' />
}
return (
<Suspense fallback={<CircularProgress />}>
<Cabinet resource={loadCabinet()} />
</Suspense>
)
}
CabinetPage.propTypes = {
loadCabinet: PropTypes.func,
failedToLoad: PropTypes.bool,
tokensRefreshFailed: PropTypes.bool,
logout: PropTypes.func,
clearTokens: PropTypes.func,
clearCabinet: PropTypes.func
}
const mapStateToProps = ({
alert,
tokens: { tokensRefreshFailed },
cabinet: { failedToLoad }
}) => ({
alert,
tokensRefreshFailed,
failedToLoad
})
const mapDispatchToProps = dispatch =>
bindActionCreators(
{
cabinetLoad: cabinetActions.load,
logout: userActions.logoutWithoutRedirect,
loadCabinet: api.loadCabinet,
clearCabinet: cabinetActions.clear,
clearTokens: tokensActions.clear
},
dispatch
)
export default connect(mapStateToProps, mapDispatchToProps)(CabinetPage)
loadCabinet()
๋ ๋์ ๋ฌธ์์์ ๋งํ๋ฏ์ด 3๋จ๊ณ ๋ ๋๋ง์ ๋น๋๊ธฐ ์์
์ ์ ๋ฌํ๊ณ read()
prop์ด ์๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
๊ทธ๋ฌ๋ ์ฌ๊ธฐ์๋ ๋ถ๋ชจ ์
๋ฐ์ดํธ๊ฐ ํ์๋์ง ์์ต๋๋ค.
@h0tw4t3r ๊ตฌ์ฑ ์์๋ฅผ ๋ ๋๋งํ๋ ๋์ Redux ์์ ์ ์ ๋ฌํ๊ณ ์์ต๋๋ค. ์ด๊ฒ์ ์ง์๋์ง ์์ผ๋ฉฐ ์ด๊ฒ์ด ๊ฒฝ๊ณ ์ ๋ํ ๊ฒ์ ๋๋ค. ์ด ๊ฒฝ์ฐ(๋ฆฌ๋๋ ์ )์ ์ ์์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ํด React Router ์ ๋ฌธ๊ฐ์๊ฒ ๋ฌธ์ํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ต๋๋ค. ํด๋น ๋ถ๋ถ์ ๋์์ด ๋์ง ์์ต๋๋ค.
๋์ ๋ชจ๋์ ๊ด๋ จํ์ฌ Redux๋ ํ์ฌ ์ผ๋ฐ์ ์ผ๋ก ํธํ๋์ง ์์ต๋๋ค. ๋ฐ๋ผ์ CM์ ์คํํ๋ ๊ฒฝ์ฐ ํผํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
ํด๋์ค์ ๋ํ ์ด ๊ฒฝ๊ณ ์ ๊ณผ๋ํ ์คํ์ ์์ ํ๋ React ํจ์น๋ฅผ ๊ณง ์ถ์ํ ์์ ์ ๋๋ค. ๋ฐ๋ผ์ ์ด๋ฌํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ฉด ๋ฉฐ์น ๊ธฐ๋ค๋ ธ๋ค๊ฐ ์ข ๋ฃ๋๋ฉด 16.13.1์ ์๋ํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์์ธ์ ๊ณ์ ์ฐพ๊ณ ์ถ๋ค๋ฉด https://github.com/facebook/react/issues/18178#issuecomment -595846312์์ ๋ฐฉ๋ฒ์ ์ค๋ช ํ๊ธฐ๋ฅผ
๋์ผํ ๋ ผ๋ฆฌ๊ฐ ํด๋์ค ๊ตฌ์ฑ ์์์์ ์ฌ์ฉ๋ ๋ ๊ธฐ๋ฅ(ํํฌ)์ด ์ํํ๋ ๋์ ๊ฒฝ๊ณ ๋ฅผ ํ์ํ์ง ์๋ ๊ฒ์ด ๋งค์ฐ ์ด์ํ๋ค๋ ๊ฒ์ ์์์ต๋๋ค.
๊ธฐ๋ฅ ๊ตฌ์ฑ ์์(ํํฌ):
import React, { Component } from "react"
import SortableTree from "react-sortable-tree"
import "react-sortable-tree/style.css"
const data = [
{
title: "Windows 10",
subtitle: "running",
children: [
{
title: "Ubuntu 12",
subtitle: "halted",
children: [
{
title: "Debian",
subtitle: "gone"
}
]
},
{
title: "Centos 8",
subtitle: "hardening"
},
{
title: "Suse",
subtitle: "license"
}
]
}
]
const nodeInfo = row => console.log(row)
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
searchString: "",
searchFocusIndex: 0,
searchFoundCount: null,
treeData: data
}
}
render() {
const { searchString, searchFocusIndex, searchFoundCount } = this.state
const customSearchMethod = ({ node, searchQuery }) =>
searchQuery &&
((node.title &&
node.title.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1) ||
(node.subtitle &&
node.subtitle.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1))
const selectPrevMatch = () =>
this.setState({
searchFocusIndex:
searchFocusIndex !== null
? (searchFoundCount + searchFocusIndex - 1) % searchFoundCount
: searchFoundCount - 1
})
const selectNextMatch = () =>
this.setState({
searchFocusIndex:
searchFocusIndex !== null
? (searchFocusIndex + 1) % searchFoundCount
: 0
})
return (
<div>
<h2>Find the needle!</h2>
<form
style={{ display: "inline-block" }}
onSubmit={event => {
event.preventDefault()
}}
>
<input
id="find-box"
type="text"
placeholder="Search..."
style={{ fontSize: "1rem" }}
value={searchString}
onChange={event =>
this.setState({ searchString: event.target.value })
}
/>
<button
type="button"
disabled={!searchFoundCount}
onClick={selectPrevMatch}
>
<
</button>
<button
type="submit"
disabled={!searchFoundCount}
onClick={selectNextMatch}
>
>
</button>
<span>
{searchFoundCount > 0 ? searchFocusIndex + 1 : 0}
/
{searchFoundCount || 0}
</span>
</form>
<div style={{ height: 300 }}>
<SortableTree
treeData={this.state.treeData}
onChange={treeData => this.setState({ treeData })}
searchMethod={customSearchMethod}
searchQuery={searchString}
searchFocusOffset={searchFocusIndex}
searchFinishCallback={matches =>
this.setState({
searchFoundCount: matches.length,
searchFocusIndex:
matches.length > 0 ? searchFocusIndex % matches.length : 0
})
}
generateNodeProps={row => {
return {
title: row.node.title,
subtitle: (
<div style={{ lineHeight: "2em" }}>{row.node.subtitle}</div>
),
buttons: [
<button
type="button"
className="btn btn-outline-success"
style={{
verticalAlign: "middle"
}}
onClick={() => nodeInfo(row)}
>
โน
</button>
]
}
}}
/>
</div>
</div>
)
}
}
ํด๋์ค ๊ตฌ์ฑ ์์:
import React from "react";
import SortableTree from "react-sortable-tree";
import "react-sortable-tree/style.css";
const data = [
{
title: "Windows 10",
subtitle: "running",
children: [
{
title: "Ubuntu 12",
subtitle: "halted",
children: [
{
title: "Debian",
subtitle: "gone"
}
]
},
{
title: "Centos 8",
subtitle: "hardening"
},
{
title: "Suse",
subtitle: "license"
}
]
}
];
const nodeInfo = row => console.log(row);
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
searchString: "",
searchFocusIndex: 0,
searchFoundCount: null,
treeData: data
};
}
render() {
const { searchString, searchFocusIndex, searchFoundCount } = this.state;
const customSearchMethod = ({ node, searchQuery }) =>
searchQuery &&
((node.title &&
node.title.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1) ||
(node.subtitle &&
node.subtitle.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1));
const selectPrevMatch = () =>
this.setState({
searchFocusIndex:
searchFocusIndex !== null
? (searchFoundCount + searchFocusIndex - 1) % searchFoundCount
: searchFoundCount - 1
});
const selectNextMatch = () =>
this.setState({
searchFocusIndex:
searchFocusIndex !== null
? (searchFocusIndex + 1) % searchFoundCount
: 0
});
return (
<div>
<h2>Find the needle!</h2>
<form
style={{ display: "inline-block" }}
onSubmit={event => {
event.preventDefault();
}}
>
<input
id="find-box"
type="text"
placeholder="Search..."
style={{ fontSize: "1rem" }}
value={searchString}
onChange={event =>
this.setState({ searchString: event.target.value })
}
/>
<button
type="button"
disabled={!searchFoundCount}
onClick={selectPrevMatch}
>
<
</button>
<button
type="submit"
disabled={!searchFoundCount}
onClick={selectNextMatch}
>
>
</button>
<span>
{searchFoundCount > 0 ? searchFocusIndex + 1 : 0}
/
{searchFoundCount || 0}
</span>
</form>
<div style={{ height: 300 }}>
<SortableTree
treeData={this.state.treeData}
onChange={treeData => this.setState({ treeData })}
searchMethod={customSearchMethod}
searchQuery={searchString}
searchFocusOffset={searchFocusIndex}
searchFinishCallback={matches =>
this.setState({
searchFoundCount: matches.length,
searchFocusIndex:
matches.length > 0 ? searchFocusIndex % matches.length : 0
})
}
generateNodeProps={row => {
return {
title: row.node.title,
subtitle: (
<div style={{ lineHeight: "2em" }}>{row.node.subtitle}</div>
),
buttons: [
<button
type="button"
className="btn btn-outline-success"
style={{
verticalAlign: "middle"
}}
onClick={() => nodeInfo(row)}
>
โน
</button>
]
};
}}
/>
</div>
</div>
);
}
}
@radulle ์ด๊ฒ์ ๊ทธ ์์ฒด๋ก ๋งค์ฐ ์ ์ฉํ ์๊ฐ ์๋๋๋ค. CodeSandbox์ ๋ฃ์ผ๋ ค๊ณ ์๋ํ์ง๋ง ์๋ํ์ง ์์ต๋๋ค: https://codesandbox.io/s/clever-taussig-9xixs. ์ฐ๋ฆฌ๊ฐ ์๋ํ ์ ์๋ ์๋ฅผ ์ค๋นํ ์ ์์ต๋๊น?
@gaearon ์ฝ๋์๋๋ฐ์ค ๋ฅผ ๋ง๋ค๊ณ ์ถ์์ง๋ง ์ต์ ๋ฒ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ์ด์ ๋ฒ์ ์์๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค. ํ์ฌ๋ก์๋ ์ด๋ฅผ ์ฌํํ๋ ์ ์ผํ ๋ฐฉ๋ฒ์ Create React App์์ ๋ก์ปฌ๋ก ํ์ ํ๋ ๊ฒ์ ๋๋ค.
@radulle CodeSandbox์์ ์๋ํ๋ ๋ฒ์ ์ ๋ฌด์์ ๋๊น?
@gaearon 2.6.2๊ฐ ์๋ํ๊ณ ๋ค์ ์ค์ ์ผ๋ก ์ค๋ฅ/๊ฒฝ๊ณ ๊ฐ ๋ฐ์ํฉ๋๋ค.
๋ฐ๋ผ์ ๋์ผํ ์ค์ ์ ๊ฒฝ์ฐ:
๊ธฐ๋ฅ ๊ตฌ์ฑ ์์: ์ค๋ฅ/๊ฒฝ๊ณ
ํด๋์ค ๊ตฌ์ฑ ์์: ์ค๋ฅ/๊ฒฝ๊ณ ์์
์ด์ฉ๋ฉด ๋ด๊ฐ ๋์น ๊ฒ์ด ์๊ณ ๊ทธ๊ฒ๋ค์ด ๋๋ฑํ์ง ์์ ์๋ ์์ต๋๋ค.
๋ค, ์ด๊ฒ์ ์ ๊ฐ https://github.com/facebook/react/issues/18178#issuecomment -600369392์์ ์ธ๊ธํ ์ฌ๋ก ์ค ํ๋์ ๋๋ค. ์ด ๊ฒฝ์ฐ ๊ฒฝ๊ณ ๋ฅผ ์์๊ฑฐํฉ๋๋ค. ๊ฒฝ๊ณ ์์ฒด๋ ํฉ๋ฒ์ ์ด๋ฉฐ ๋น์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋งํ๋ฏ์ด ๊ฐ๋ ์ ์ผ๋ก ์์ ์์๋ ๋ฌธ์ ์ ๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ง๊ธ์ (์ด ์์์๋, ๊ทธ๊ฒ์ด) ํด๋์ค์์ ์ค๋ ๋๋ฅผ ์ํด ๋ ๊ฒฝ์ฐ ๋ชจ๋ ๊ทธ๊ฒ์ ์์๊ฑฐ ๊ฒ ๋๋ฌธ์ ๊ทธ๋ฌ๋, ์ฐจ์ด๋ ์ดํด๊ฐ๋์ง ์์ต๋๋ค.
ํจ๊ณผ๊ฐ ์๋ ๋ ๋๋ง ๊ธฐ๋ฅ์์ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ์คํํ๋ ํฉ๋ฒ์ ์ธ ์ฌ์ฉ ์ฌ๋ก๊ฐ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ฆ, ์คํ ์์๋ฅผ ์ ์งํ๊ธฐ ์ํ ๊ฒ์ ๋๋ค.
์ค์ฉ์ ์ธ ์๋ฅผ ๋ค์ด ์ค๋ช ํ์๋ฉด: ์ฐ๋ฆฌ ์ฑ์๋ ์ด๋ ๊ฒฝ๋ก๋ฅผ ๊ด๋ฆฌํ๋ ๋ ํนํ ์์คํ ์ด ์์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ด ์ปจํ ์คํธ์ ์ด๋ ๊ฒฝ๋ก๋ฅผ ์ถ๊ฐํ ์ ์๋ ํํฌ๊ฐ ์์ต๋๋ค.
const addBreadcrumb = useAddBreadcrumb();
addBreadcrumb(<Breadcrumb>{item.name}</Breadcrumb>, [item.name]);
์ด๊ฒ์ ์ด๋ ๊ฒฝ๋ก ๊ตฌ์กฐ๋ฅผ ์ ์งํ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ ๋งค์ฐ ์ค์ฉ์ ์ ๋๋ค. ์ด ๊ตฌ์กฐ๋ ์ฝ๋ ์์ฒด์์ ์ ์ธ๋ฉ๋๋ค. ๊ฒฝ๋ก๋ฅผ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ๋ถ๋ถ์ผ๋ก ์ด๋ํ๋ ค๋ ๊ฒฝ์ฐ ์ด๋ ๊ฒฝ๋ก ์์คํ ์ ๊ณ์ ์๋ํฉ๋๋ค.
๋ฐ๋ผ์ react-router
์ ๊ฒฐํฉํ์ฌ ๋ค์๊ณผ ๊ฐ์ด ํ ์ ์์ต๋๋ค.
// Main/index.tsx
import { useAddBreadcrumb } from 'components/Breadcrumbs';
import React from 'react';
import Home from './Home';
import Movies from './Movies';
const Main = () => {
const addBreadcrumb = useAddBreadcrumb();
addBreadcrumb(<Breadcrumb to="/">Home</Breadcrumb>, []);
return <Switch>
<Route path="/movies">
<Movies />
</Route>
<Route path="/" />
<Home />
</Route>
</Switch>
}
// Movies/index.tsx
import { useAddBreadcrumb } from 'components/Breadcrumbs';
import React from 'react';
import Detail from './Detail';
import Master from './Master';
const Movies = ({ url }) => {
const addBreadcrumb = useAddBreadcrumb();
addBreadcrumb(<Breadcrumb to={url}>Movies</Breadcrumb>, [url]);
return <Switch>
<Route path="/:id">
<Detail />
</Route>
<Route path="/" />
<Master />
</Route>
</Switch>
}
// Movies/Detail/index.tsx
import Breadcrumbs, { useAddBreadcrumb } from 'components/Breadcrumbs';
import React from 'react';
import { useRouteMatch } from 'react-router-dom';
const MovieDetail = ({ url }) => {
const addBreadcrumb = useAddBreadcrumb();
const { params: { id } } = useRouteMatch<{ id: string; }>();
const movie = useMovie(id);
addBreadcrumb(
<Breadcrumb to={url}>{movie?.name}</Breadcrumb>,
[movie?.name, url]
);
return <div>
<Breadcrumbs />
</div>
}
์ด์ /movies/gone-with-the-wind
๋ก ์ด๋ํ๋ฉด ์ด๋ ๊ฒฝ๋ก๊ฐ ๋ค์๊ณผ ๊ฐ์ด ํ์๋ฉ๋๋ค.
Home > Movies > Gone with the wind
์, ์ฌ๊ธฐ ๋ด ์์ ์ด ์์ต๋๋ค. ์ด๊ฒ์ด ์๋ํ๋ ค๋ฉด ์คํ ์์๊ฐ ๋ณด์ฅ๋์ด์ผ ํฉ๋๋ค. ์ด ๊ฒฝ์ฐ ์คํ ์์๋ ๋ถ๋ช
ํฉ๋๋ค. ๋จผ์ Main
๋ ๋๋ง๋ ๋ค์ Movies
๋ฅผ ํฌํจํ๋ ์์์ด ๋ ๋๋ง๋๊ณ ๋ง์ง๋ง์ผ๋ก MovieDetail
๋ ๋๋ง๋ฉ๋๋ค. ์ด ๊ฒฝ์ฐ addBreadcrumb
ํธ์ถ์ด ์ฌ๋ฐ๋ฅธ ์์๋ก ์คํ๋ฉ๋๋ค.
์ด์ ๋ณ๊ฒฝ ๋ก๊ทธ์ ๋ค์๊ณผ ๊ฐ์ด ๋์ ์์ต๋๋ค.
๋ ๋๋ง ๊ฒฐ๊ณผ๋ก ๋ค๋ฅธ ๊ตฌ์ฑ ์์์ ์ํ๋ฅผ ์๋์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ค๋ ๋๋ฌธ ๊ฒฝ์ฐ์ setState ํธ์ถ์ useEffect๋ก ๋ํํ ์ ์์ต๋๋ค.
์ด๊ฒ์ ์ค์ ๋ก ๋ค๋ฅธ ๊ตฌ์ฑ ์์์ ์ํ๋ฅผ ์๋์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ค๋ ๋๋ฌธ ๊ฒฝ์ฐ ์ค ํ๋์
๋๋ค. ๊ทธ๋ฌ๋ ๋ณ๊ฒฝ ๋ก๊ทธ๊ฐ ์ ์ํ๊ณ addBreadcrumb
(๊ฒฐ๊ตญ setState
) ๋ฅผ useEffect
๋ก ๊ฐ์ธ๋ฉด ์คํ ์์๊ฐ ๋ ์ด์ ๋ณด์ฅ๋์ง ์์ต๋๋ค. ์ธ ๊ฐ์ง setStates
๋ชจ๋ ๋ ๋๋ง์ด ์๋ฃ๋ ํ ์คํ๋์ด ๊ฒฝ์ ์กฐ๊ฑด์ด ์์ฑ๋๊ณ ์์คํ
์ด ์ค๋จ๋ฉ๋๋ค.
์ด ๋ ํนํ ์์คํ ์ด ์ํฐ ํจํด์ผ๋ก ๊ฐ์ฃผ๋๋์ง ์ฌ๋ถ๋ ๋ชจ๋ฅด๊ฒ ์ง๋ง ๋์๊ฒ๋ ์๋ฏธ๊ฐ ์์ผ๋ฉฐ ๋ ๊ฐ๋จํ ๋์์ ์ฐพ์ง ๋ชปํ์ต๋๋ค.
๊ทธ๋์ ๊ฒฐ๋ก ์ ์ผ๋ก ๋๋ ์ด ์๋ก์ด ๊ฒฝ๊ณ ๋ฅผ ํ์ํ์ง๋ง, ์ฐ๋ฆฌ์๊ฒ ์ต์ ์ ํด๊ฒฐ์ฑ
์ ๊ทธ๊ฒ์ ์ต์ ํ ๋ฐฉ๋ฒ์ ๊ฐ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. setState
๋ํ ๋ ๋ฒ์งธ ์ ํ์ ๋งค๊ฐ๋ณ์๊ฐ ํธ๋ฆญ์ ์ํํ ์ ์์ต๋๋ค.
@MeLlamoPablo
ํ์ ๋๋ ๋ถ๋ชจ/์์ ๋ ๋๋ง ์์์ ๋ ๋ ํธ์ถ์ ์์กดํ๋ ๊ฒ์ ๋งค์ฐ ์ทจ์ฝํ๊ฒ ๋ค๋ฆฝ๋๋ค. React๋ ์ค์ ๋ก ์ด๊ฒ์ ๋ณด์ฅํ์ง ์์ต๋๋ค. ์ด๋ฆฐ์ด๋ ๋ถ๋ชจ ์์ด ๋ค์ ๋ ๋๋งํ ์ ์์ผ๋ฉฐ ๊ทธ ๋ฐ๋๋ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค. ์์์ด ์ง์ฐ์ผ๋ก ๋ ๋๋ง๋๋ฉด(์: ์ฝ๋ ๋ถํ ) ์ด ์ฝ๋๋ ์ค๋จ๋ฉ๋๋ค. ๋๋ ์ผ๋ถ ์์์ด ๋์ ์ผ๋ก ์ฝ์ ๋๊ฑฐ๋ ์ญ์ ๋๋ ๊ฒฝ์ฐ. ๋งํ ๊ฒ๋ ์์ด, ์ด๊ฒ์ ๊ณ๋จ์ ๋ ๋๊ฐ ๋๋ฌด ๋ง๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ ๋ฉด์์ ์๋นํ ์ข์ง ์์ต๋๋ค.
๋๋ ๋น์ ์ด ํด๊ฒฐํ๋ ค๋ ๋ฌธ์ ์ ๊ณต๊ฐํฉ๋๋ค. ์ค์ ๋ก ์ค๋๋ React์๋ ๊ด์ฉ์ ์๋ฃจ์ ์ด ์์ต๋๋ค. ์ด์ ๋ํ ๋ช ๊ฐ์ง ์์ด๋์ด๊ฐ ์์ง๋ง ์ ์ ํ ์๋ฃจ์ ์ ์๋นํ ๋ฌ๋ผ์ผ ํฉ๋๋ค. ๊ทธ๋์ ์ด ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค.
@gaearon , ํต์ฐฐ๋ ฅ ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค. ํ ๊ฐ์ง ์ง๋ฌธ์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ๋ ๋๋ง์ ์์๊ฐ ๋ณด์ฅ๋ฉ๋๊น? ๊ทธ๊ฒ์ด ์ฐ๋ฆฌ๊ฐ ์ ๋๋ก ์๋ํ๋ ๋ฐ ํ์ํ ์ ๋ถ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค(ํ ๋ฒ ์ด๋ ๊ฒฝ๋ก๋ฅผ ์๊ณ ๋๋ฉด ํ์ ๋ ๋๋ง์ ์์๋ ์ ๊ฒฝ ์ฐ์ง ์์ต๋๋ค).
์ฒซ ๋ฒ์งธ ๋ ๋๋ง์ ์์๊ฐ ๋ณด์ฅ๋๋ค๋ ๊ฒ์ด ๋ ผ๋ฆฌ์ ์ผ๋ก ๋ณด์ ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด React๊ฐ ๋ถ๋ชจ ๊ตฌ์ฑ ์์์ ์์์ด ์๋ค๋ ๊ฒ์ ์ด๋ป๊ฒ ์ ์ ์์ต๋๊น?
๊ณ๋จ์ ๋ ๋์ ์ฑ๋ฅ์ ๋ํด์๋ ์ ์ ์ผ๋ก ๋ง์ต๋๋ค. ์์คํ ์ ๊ฐ์ ํ ์ ์๋ ๋ฐฉ๋ฒ์ ์ฐพ์ ๊ฒ์ ๋๋ค.
@MeLlamoPablo
ํ ๊ฐ์ง ์ง๋ฌธ์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ๋ ๋๋ง์ ์์๊ฐ ๋ณด์ฅ๋ฉ๋๊น? ๊ทธ๊ฒ์ด ์ฐ๋ฆฌ๊ฐ ์ ๋๋ก ์๋ํ๋ ๋ฐ ํ์ํ ์ ๋ถ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค(ํ ๋ฒ ์ด๋ ๊ฒฝ๋ก๋ฅผ ์๊ณ ๋๋ฉด ํ์ ๋ ๋๋ง์ ์์๋ ์ ๊ฒฝ ์ฐ์ง ์์ต๋๋ค).
๊ฐ๋ ฅํ์ง ์์ต๋๋ค. ๋๋ ๊ทธ๊ฒ์ด ๋๋ถ๋ถ ํ์ฌ ๋ฒ์ ์ React์์ ์๋ํ๋ค๊ณ ์๊ฐํ์ง๋ง ๋ฏธ๋์๋ ๋ฐ๋ ์ ์์ต๋๋ค. ์ค๋๋ ์๋ lazy
๋ฐ Suspense
์ ๊ฐ์ ๊ธฐ๋ฅ๊ณผ ๊ฒฐํฉํ์ฌ ๋ณด์ฅ๋์ง ์์ต๋๋ค.
๊ทธ๋ ์ง ์์ผ๋ฉด React๊ฐ ๋ถ๋ชจ ๊ตฌ์ฑ ์์์ ์์์ด ์๋ค๋ ๊ฒ์ ์ด๋ป๊ฒ ์ ์ ์์ต๋๊น?
ํ์ ์๋งค ์์๋ ๋ณด์ฅ๋์ง ์์ต๋๋ค. ๋ถ๋ชจ/์์ ์์์ ๊ฒฝ์ฐ ๋ถ๋ชจ ๊ฐ ๋จผ์ ๋ ๋๋ง ํ๊ธฐ ์ ์ ๋๋ ์ฒซ ๋ฒ์งธ ์์์ ๋ ๋๋งํ ํ์๋ ๋ ๋ฒ์งธ ์์๋ณด๋ค ๋จผ์ ๋ถ๋ชจ๋ฅผ ๋ค์ ๋ ๋๋งํด์ผ ํ ์๋ ์์ต๋๋ค. ๋ค์ ๋งํ์ง๋ง, ์ฝ๋ ๋ถํ ๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ฉด ๋ ๋นจ๋ฆฌ ๋ณด์ฅ์ ์๊ฒ ๋ฉ๋๋ค.
์ด๊ฒ์ ๊นจ์ง๊ธฐ ์ฝ์ต๋๋ค.
@gaearon๋ , ๋ค์ ํ๋ฒ ๊ฐ์ฌ๋๋ฆฝ๋๋ค. ์ด๊ฒ์ ๋งค์ฐ ๊ฐ์ฌํฉ๋๋ค.
๋ ๋๋ง ๋ณธ๋ฌธ ๋ด์์ useState
mutators ํธ์ถ์ ๋ํด ๊ฒฝ๊ณ ํ๋ ESLint ๊ท์น์ด ์์ด์ผ ํฉ๋๊น?
(์ด ์๊ปด์ ์ฌ์ฉํด์ผํ์ง๋ง) ๋ ๋๋งํ๋ ๋์ ์์ ์ ๊ตฌ์ฑ ์์์ setState๋ฅผ ํธ์ถํ๋ฉด ์ง์๋๋ ํจํด์ด๋ค. ๋์ ๋ค๋ฅธ ๊ตฌ์ฑ ์์์ setState์ ๋๋ค. ์ ์ ์ผ๋ก ๊ฐ์งํ ์ ์์ต๋๋ค.
์ด๋ก ์ ์ผ๋ก ts-eslint๋ฅผ ์ฌ์ฉํ์ฌ ์ํํ ์ ์์ต๋๋ค. ์ฌ๋ฐ๋ฅธ ์ ์คํธ๋ฆผ React ์ ํ์ ์ฌ์ฉํ๊ณ ์๋ค๊ณ ๊ฐ์ ํ ๋ ๊ทธ๋ ์ต๋๋ค. ํ์ง๋ง ์๋ง๋ ๊ฐ์น๊ฐ ์๋ ๊ฒ๋ณด๋ค ๋ ๋ง์ ๋ ธ๋ ฅ์ด ํ์ํ ๊ฒ์ ๋๋ค.
์ผ์ข ์ ํจ๊ณผ ์ถ์ ์์ด๋ ๋ถ๊ฐ๋ฅํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ค๊ฐ์ ๊ธฐ๋ฅ์ด ํ๋ ์์ผ๋ฉด ์ ๋ณด๋ฅผ ์๊ฒ ๋ฉ๋๋ค.
๋๋ ๋ํ
react@experimental
+react-redux
+redux
์ด ๋ฌธ์ ์ ์ง๋ฉดํ๊ณ ์์ต๋๋ค.์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
import React, { Suspense } from 'react' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' import { Redirect } from 'react-router-dom' import PropTypes from 'prop-types' import { userActions, cabinetActions, tokensActions } from '../../actions' import { CircularProgress } from '@material-ui/core' import { api } from './api' const Cabinet = ({ resource }) => { resource.read() return <h1>cabinet</h1> } Cabinet.propTypes = { resource: PropTypes.shape({ read: PropTypes.func }) } const CabinetPage = ({ failedToLoad, tokensRefreshFailed, logout, loadCabinet, clearTokens, clearCabinet }) => { if (tokensRefreshFailed || failedToLoad) { clearTokens() clearCabinet() logout() return <Redirect to='/login' /> } return ( <Suspense fallback={<CircularProgress />}> <Cabinet resource={loadCabinet()} /> </Suspense> ) } CabinetPage.propTypes = { loadCabinet: PropTypes.func, failedToLoad: PropTypes.bool, tokensRefreshFailed: PropTypes.bool, logout: PropTypes.func, clearTokens: PropTypes.func, clearCabinet: PropTypes.func } const mapStateToProps = ({ alert, tokens: { tokensRefreshFailed }, cabinet: { failedToLoad } }) => ({ alert, tokensRefreshFailed, failedToLoad }) const mapDispatchToProps = dispatch => bindActionCreators( { cabinetLoad: cabinetActions.load, logout: userActions.logoutWithoutRedirect, loadCabinet: api.loadCabinet, clearCabinet: cabinetActions.clear, clearTokens: tokensActions.clear }, dispatch ) export default connect(mapStateToProps, mapDispatchToProps)(CabinetPage)
loadCabinet()
๋ ๋์ ๋ฌธ์์์ ๋งํ๋ฏ์ด 3๋จ๊ณ ๋ ๋๋ง์ ๋น๋๊ธฐ ์์ ์ ์ ๋ฌํ๊ณread()
prop์ด ์๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
๊ทธ๋ฌ๋ ์ฌ๊ธฐ์๋ ๋ถ๋ชจ ์ ๋ฐ์ดํธ๊ฐ ํ์๋์ง ์์ต๋๋ค.
์ด ๋ฌธ์ ๊ฐ ์๋ ๋ค๋ฅธ ์ฌ๋์ ๊ฒฝ์ฐ redux ์์ ๋์คํจ์น๋ฅผ โโ๋ฐํ๋ ๊ตฌ์ฑ ์์๋ก ์ด๋ํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค. ํ์ฌ ๋ชจ์ต์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
const CabinetPage = ({
alert,
failedToLoad,
tokensRefreshFailed,
logout,
loadCabinet,
clearTokens,
clearCabinet,
clearAlert
}) => (
<Suspense fallback={<MUIBackdropProgress />}>
{alert.message && (failedToLoad || tokensRefreshFailed) ? (
<MUIAlertDialog
title={alert.message}
text={errorText}
onClose={() => {
clearAlert()
clearCabinet()
clearTokens()
logout()
}}
/>
) : (
<Cabinet resource={loadCabinet()} />
)}
</Suspense>
)
์ด ๊ฒฝ๊ณ ๊ฐ ๋ง์์ ๋๋ ์ด์ ๋ ์ฌ๋ฐ๋ฅธ ๋์์ธ ํจํด์ ์ ํํ๋๋ก ํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด์ ๋ชจ๋ ๊ฒ์ด ์๋ฒฝํ๊ฒ ์๋ํฉ๋๋ค!
16.13.1์์ ๊ฒฝ๊ณ ๊ฐ ๊ณผ๋ํ๊ฒ ๋ฐ์ํ๋ ๊ฒฝ์ฐ๋ฅผ ์์ ํ์ต๋๋ค. ๋๋จธ์ง ์ฌ๋ก๋ ํฉ๋ฒ์ ์ด๋ฉฐ ์์ ํด์ผ ํฉ๋๋ค.
@gaearon์ด ๋ฐฉ๊ธ ์ ๊ทธ๋ ์ด๋๋๊ณ ์ค๋ฅ๊ฐ ์ฌ๋ผ์ก์ต๋๋ค! ๋น์ ์ ์์ ์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค!
@gaearon ๊ฐ์ฌํฉ๋๋ค. ๋น์ ์ ๋ฐฉ๊ธ ๋ด ํ๋ฃจ๋ฅผ ๊ตฌํ์ต๋๋ค :-)
์ ๊ทธ๋ ์ด๋ํด๋ ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์ง ์์์ง๋ง ์ฝ์์์ ๋ฌธ์ ๋ฅผ ์ฐพ๋ ๋ฐ ๋์์ด ๋๋ ์ถ๊ฐ ์ ๋ณด๋ฅผ ์ ๊ณตํ์ต๋๋ค. @gaearon ๊ฐ์ฌ
๋ค๋ฅธ ๊ตฌ์ฑ ์์๊ฐ ์ง๋๋ฒ๊ณผ ๋์ผํ ์ํ๋ฅผ ๋ฐํํ๋๋ก ํ๋ ์์ ์ ์ ๋ฌํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ๋์ ๊ฒ์ผ๋ก ๊ฐ์ฃผ๋ฉ๋๊น? ๊ทธ๋ฐ ๊ฒฝ์ฐ์๋ ๋จ๋ฝ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
๋๋ ์์ ํ์ด ๊ฒฝ๊ณ ๋ค์ ๋ ผ๋ฆฌ๋ฅผ ์ดํดํ๋ฉด์ ๋ ๊ทธ๋ฅ์ด ์๋ค๊ณ ๋งํ ์ ... ๊ฑฐ์ ํ์ด ์ฝ๋์ ๋ฐฉ๋ฒ์ ๋ํ ์ด๋ฌํ ์ค์ํ ์ง๋ฆฌ๋ฅผ ๊ฐ๋ฅด์ณ ์ค ๊ฒ์ฒ๋ผ ๋๋ ๋๋ฌธ์์ด ํ์ด ์ง์ญ ์ฌํ๋ฅผ ๋งํ๊ณ ์๋ค ๋ฐ์์ฉ ๋ฌด์์ ๋ฐฐ์ ๊ฐ์ ๋๋ ๋ฐ์:
1) ๊ณ์ธต ๊ตฌ์กฐ์์ ํ์ํ ๋งํผ ๋์ ์ํ๋ฅผ ์ ์งํ๊ณ (๋์ง ์์) ๋ฐ์ดํฐ ์ ์ค์ ์ ๋ฅผ ํ์ ๊ตฌ์ฑ ์์๋ก ์ ๋ฌํฉ๋๋ค.
2) ๊ธฐ๋ฅ ๊ตฌ์ฑ ์์๊ฐ ๊ต์ฅํฉ๋๋ค! ํด๋์ค ๋ ธ์ด์ฆ๋ ์์ด๋ฒ๋ฆฌ๊ณ ์ ์ฒด ๊ตฌ์ฑ ์์๋ฅผ ํ๋์ ๊ธฐ๋ฅ์ผ๋ก ์ํํ์ญ์์ค!
์ด์ ์ฌ๋๋ค์ด ์ด ๋ ๊ฐ์ง ๊ท์น์ ๋ฐ๋ฅด๊ณ ์ํ ์ค์ ์๋ฅผ ํจ์ ๊ตฌ์ฑ ์์๋ก ์ ๋ฌํ๊ณ ํด๋น ๊ตฌ์ฑ ์์์์ ํธ์ถํ๋ฉด ... ๋น์ ์ ๊น๊ฐ๋ฅผ ๊บผ๋ด๊ณ "ํํ, ํ์ง๋ง ์ฐ๋ฆฌ๊ฐ ๋งํ ๊ฒ์ ์ค์ ๋ก ํ ์๋ ์์ต๋๋ค. ํ ๊ฒ".
์ด ์ค ์ด๋ ๊ฒ๋ ์ฌ๊ธฐ์ ๊ธฐ์ ์ ์ธ ์๊ตฌ ์ฌํญ์ ๋ํด ์๋ฌด ๊ฒ๋ ๋ณ๊ฒฝํ์ง ์์ผ๋ฉฐ ์ด ๋ณ๊ฒฝ์ ๋ํด ์๋ฌด ๋ง๋ ํ์ง ์์ต๋๋ค. ์ด ๋ณ๊ฒฝ ์ฌํญ์ด ์๋ชป๋์๊ฑฐ๋ ๋์๋ค๊ณ ๋งํ๋ ๊ฒ์ด ์๋๋๋ค ... ๋๋ ๋จ์ง ๋ฉ์์ง ๋ฌธ์ ๊ฐ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋ฐฉ๊ธ ์ธ๊ธํ์ต๋๋ค) ์ด ์๋ก์ด ์ธ๊ณ์์ ์ฝ๋ฉํ๊ธฐ ์ํ ๊ฒ์ ๋๋ค. ์ฐ๋ฆฌ์ ๋ํ ๊ท์น์ ๋ณ๊ฒฝํ๋ ค๋ ๊ฒฝ์ฐ ๋จผ์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ค๋ช ํ์ฌ ๋ณ๊ฒฝํ๋ ๋ฐ ๋์์ด ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
๊ทธ๋์ ์ ๊ฐ ์ ๋ง๋ก ๋ฌป๊ณ ์ถ์ ๊ฒ์ ... ํ์ ๋๊ตฐ๊ฐ๊ฐ "์ด์ ์ ์ฐ๋ฆฌ๊ฐ ๋ ๊ฐ์ง ๊ท์น์ ์ค ๊ฒ์ ์๋๋ค. ์ ๊ท์น"์ ํด๋ฆญํ ๋ค์ ์ด ์๋ก์ด ๊ฒฝ๊ณ ๋ฅผ ์ฐธ์กฐํ๋ ๋ฌธ์/๋ฆด๋ฆฌ์ค ๋ ธํธ์ ๋ชจ๋ ์์น์ ํด๋น ๋ฌธ์์ ๋ํ ๋งํฌ๋ฅผ ์ถ๊ฐํฉ๋๋ค(๋ฐ๋ผ์ "WTF๊ฐ ์ด๊ฒ์ด?"๋ผ๊ณ ์ธํฐ๋ท ๊ฒ์์ ํ๋ ๋ชจ๋ ์ฌ๋์ "์๋ก์ด ์ธ๊ณ").
@machineghost : ๋ฉ์์ง๊ฐ ๊ฒฝ๊ณ ํ๋ ๋ด์ฉ์ ์คํดํ๊ณ ์๋ ๊ฒ ๊ฐ์ต๋๋ค.
๋ถ๋ชจ์ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ๋ ์ฝ๋ฐฑ์ ์์์๊ฒ ์ ๋ฌํ๋ ๋ฐ ์๋ฌด๋ฐ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ํญ์ ๊ด์ฐฎ์์ต๋๋ค.
๋ฌธ์ ๋ _์ฒซ ๋ฒ์งธ ๊ตฌ์ฑ ์์๊ฐ ๋ ๋๋ง๋๋ ๋์_ ํ ๊ตฌ์ฑ ์์๊ฐ ๋ค๋ฅธ ๊ตฌ์ฑ ์์์ ์ ๋ฐ์ดํธ๋ฅผ ๋๊ธฐ์ด์ ๋ฃ์ ๋์ ๋๋ค.
์ฆ, ๋ค์๊ณผ ๊ฐ์ด ํ์ง ๋ง์ญ์์ค.
function SomeChildComponent(props) {
props.updateSomething();
return <div />
}
๊ทธ๋ฌ๋ ์ด๊ฒ์ ๊ด์ฐฎ์ต๋๋ค.
function SomeChildComponent(props) {
// or make a callback click handler and call it in there
return <button onClick={props.updateSomething}>Click Me</button>
}
๊ทธ๋ฆฌ๊ณ Dan์ด ์ฌ๋ฌ ๋ฒ ์ง์ ํ๋ฏ์ด ๋ ๋๋งํ๋ ๋์ _same_ ๊ตฌ์ฑ ์์์ ์ ๋ฐ์ดํธ๋ฅผ ๋๊ธฐ์ด์ ๋ฃ๋ ๊ฒ๋ ๊ด์ฐฎ์ต๋๋ค.
function SomeChildComponent(props) {
const [number, setNumber] = useState(0);
if(props.someValue > 10 && number < 5) {
// queue an update while rendering, equivalent to getDerivedStateFromProps
setNumber(42);
}
return <div>{number}</div>
}
๋ง์ต๋๋ค. ํ์ง๋ง ๊ตฌ์ฑ ์์๋ฅผ ์ฝ๋ฉํ ๋ ์์ ์์์ ํ์ด๋ฐ์ ์๊ฐํ์ง ์์ต๋๋ค. ์ด๊ฒ์ด React ๊ตฌ์ฑ ์์์ ์๋ฆ๋ค์์ ์ผ๋ถ์ธ ์บก์ํ์ ๋๋ค.
๋ค์ ๋งํ์ง๋ง, ์๋ก์ด ๊ฒฝ๊ณ ๊ฐ ์ ํ ๋์๋ค๊ณ ๋งํ๋ ๊ฒ์ด ์๋๋๋ค. ์ข์ React ๊ฐ๋ฐ์๊ฐ ๋ฐ๋ฅผ ์ ์๋ ๋ ๊ฐ์ง ๊ท์น์ด ์๊ธฐ ์ ์ ๋งํ๋ ๊ฒ์ ๋๋ค. ์ด์ X ์กฐ๊ฑด์์ ์ด๋ฌํ ๊ท์น์ ์ฐฝ ๋ฐ์ผ๋ก ๋๊ฐ์ง๋ง X ์๋์์๋ง(X = "๋ถ๋ชจ ๊ตฌ์ฑ ์์๋ ์ ๋ฐ์ดํธ๋๋ ๋์"์ฒ๋ผ ๋ค๋ฆผ).
๊ทธ๋ฅ "์ด๊ฒ ๋ฌธ์ ์ผ!"๋ผ๊ณ ๋งํ๋ ๊ฒ๋ณด๋ค ๊ทธ๊ฒ์ ์ค๋ช ํ๊ณ ๋ฌธ์ ๋ฅผ ํผํ๋ ๋ฐฉ๋ฒ์ ๋ ์ง์คํด์ผํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
@machineghost : ๋น์ ์ _์ ๋ง_ ๋ด๊ฐ ์ฌ๊ธฐ์ ๋งํ๋ ๊ฒ์ ์ดํดํ์ง ๋ชปํ๊ณ ์์ต๋๋ค.
๋ถ๋ชจ/์์ ํ์ด๋ฐ์ด ๋ฌธ์ ๊ฐ ์๋๋๋ค.
ํจ์ ๊ตฌ์ฑ ์์๋ฅผ ๋ ๋๋งํ๋ ๋์ _๋ค๋ฅธ ๊ตฌ์ฑ ์์์์ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ๋๊ธฐ์ด์ ๋ฃ๋ ๊ฒ์ด ๋ฌธ์ ์ ๋๋ค.
์ ์์ ๋ฐ๋ฅด๋ฉด ๋ถ๋ชจ/์์(๋๋ ์์)์ด์ด์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ํ ์ค์ ์๋ฅผ ์ ๋ฌํ ์ ์์ต๋๊น?
์ด๊ฒ์ด ๋ค๋ฅธ ๊ตฌ์ฑ ์์ ๊ด๊ณ์์๋ ๋ฌธ์ ๊ฐ ๋ ์ ์๋ค๊ณ ๋งํ๋ ๊ฒ์ด ์๋๋ผ React ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๊ณ ์ํ ์ค์ ์๋ฅผ ์ ๋ฌํ ๋ค์ ์ด ๊ฒฝ๊ณ ๋ฅผ ๋ฐ๋ ์ฌ๋๋ค์ ๋ํด ๊ตฌ์ฒด์ ์ผ๋ก ์ด์ผ๊ธฐํ๋ ๊ฒ์ ๋๋ค.
๊ทธ๊ฒ์ด ๋ด๊ฐ ๋งํ๋ ์ ๋ถ์ด๋ฉฐ, ๋ด๊ฐ ๋งํ๋ ์ ๋ถ๋ "์ฌ๊ธฐ์ '์๋ก์ด ์ค๋ฅ๊ฐ ์์ผ๋ฉฐ ์ด๊ฒ์ด ์๋ฏธํ๋ ๋ฐ'๊ฐ ์๋๋ผ ์ฝ๋๋ฅผ ์ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋ ์ค์ ์ ๋์ด ๋ ์ ์ค๋ช ํ ์ ์์ต๋๋ค."์ ๋๋ค.
ํ์ด๋ฐ. ์๋๋ค. ๋ฌธ์ .
ํจ์ ๊ตฌ์ฑ ์์๋ ๋ ๋๋งํ๋ ๋์ ์์ฒด์ ์ผ๋ก๋ง ์ํ ์
๋ฐ์ดํธ๋ฅผ ๋๊ธฐ์ด์ ๋ฃ์ getDerivedStateFromProps
์ ๋์ผํ ์ญํ ์ ํฉ๋๋ค.
ํจ์ ๊ตฌ์ฑ ์์์ ์ค์ ๋ ๋๋ง ๋ณธ๋ฌธ ๋ด์์ _any_ ๋ค๋ฅธ ๊ตฌ์ฑ ์์์ ๋ํ ์ ๋ฐ์ดํธ๋ฅผ ๋๊ธฐ์ด์ ๋ฃ๋ ๊ฒ์ ๋ถ๋ฒ์ ๋๋ค.
์ด๊ฒ์ด ์ด ๊ฒฝ๊ณ ๊ฐ ๋งํ๋ ๊ฒ์ ๋๋ค.
์ด๋ป๊ฒ ๋ ๋ช ํํ๊ฒ ์ค๋ช ํ ์ ์์์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค.
ํ์ด๋ฐ์ด ๋ฌธ์ ๊ฐ ์๋๋๋ค. ๋น์ ์ ๊ฒ์ด ์๋๋ผ ์ ๊ฒ์ด ์๋๋๋ค. ๋ด ๋ฌธ์ ๋ ๋ฌธ์ ๋๋ ๋ฌธ์ ๋ถ์กฑ์ ๋๋ค.
๊ทธ๋ฌ๋ ๋น์ ์ ๊ทธ๋ค์ด ๋งํ๋ ๊ฒ์ ๋ฃ๋ ๋์ ์ธํฐ๋ท ๋ฏ์ ์ฌ๋๊ณผ์ ๋ฌธ์ ์ค๋ ๋์์ ์ ์์ ์์ํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค.
์์ ์ ๋ณ๊ฒฝ๋ ๊ท์น์ด ์๋ค๋ ๊ฒ์ ๋๋ค. ์ด๊ฒ์ ํญ์ ์๋ชป๋ ํจํด์ด์์ต๋๋ค. ์ฝ๋์ ๋ฒ๊ทธ๊ฐ ์์์ ์ ์ ์๋๋ก ๊ฐ์กฐ ํ์๋ฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ง ๊ทธ๋๋ก ๋น์ ์ด ๋ฐฉ๊ธ ๋งํ ์ด๋ค ๊ฒ๋ ๋ด๊ฐ ์ด ๊ฒ๊ณผ ์ผ์นํ์ง ์์ต๋๋ค. ์ฌ์ค, ๊ทธ ๊ฐ์ ๊ท์น์ ๋ ์ ์ค๋ช , ๋น์ ์ ๋ณ๊ฒฝ๋์ง ์์ ๋ง ์ฌ๋์ด์๋ค (๋ฌผ๋ก ๋ด๊ฐ ์ฒ์๋ถํฐ ๋๊ฐ์ ์ผ์ ๋งํ ... ๋ชจ๋ ๋ด๊ฐ ๋ชจ๋ ์๊ฐ์ ์๊ตฌ ๊ฑฐ์ ๊ฐ๋ค ๊ทธ๋ค์ ๋ณ๊ฒฝ ํ์ง ์์ ์ผ๋ฉฐ "์๋ก์ด ์ธ์์ ๋ง๋ค์๋ค"๋ ๊ฒฝ๊ณ ์์ต๋๋ค).
์ถ์ : ๋น์ ๋ ์ฌ๊ธฐ์ ์์ด๋ฌ๋๋ฅผ ๊นจ๋ซ์ง ๋ชปํ๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋ด๊ฐ ์ดํดํ์ง ๋ชปํ๋ ๊ฒ์ด ์์ผ๋ฉด ๋ฌธ์๋ฅผ ๊ฐ์ ํ ์ ์์ต๋๋ค. ๋ด๊ฐ ์ฌ๋ฌผ์ ์ผ๋ง๋ ์ ์ดํดํ์ง ๋ชปํ๋ค๊ณ ๋์๊ฒ ์๋ฆฌ์น๋ ๊ฒ์ ๋์ ์ง์๋ฅผ ๊ฐํ์ํฌ ๋ฟ์ ๋๋ค. ๋ฌธ์๋ฅผ ๋ง์ ์ฒ๋ผ ํฅ์์ํค์ง๋ ์์ต๋๋ค.
์๋ ํ์ธ์ ์ฌ๋ฌ๋ถ, ์กฐ๊ธ ์ง์ ํฉ์๋ค. ๐
@markerikson ์ฐธ์ฌํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค. ํ์ง๋ง ์ด ํ ๋ก ์ด ๋๋ฌด ๊ณผ์ด๋๊ณ ์๋ ๊ฒ ๊ฐ์ต๋๋ค.
@machineghost ์ฐ๋ ค๋ฅผ ํ๋ช
์ด ๊ฒฝ๊ณ ์๋ ์ฌ์ ์ปจํ ์คํธ๊ฐ ํ์ํ๋ค๋ ๋ฐ ๋์ํฉ๋๋ค. ๋ณธ์ง์ ์ผ๋ก, ๋น์ ์ ์์ ์๋๋ถํฐ ๋ ๊ฐ์ง๋ฅผ ์์์ผ ํ์ต๋๋ค.
๋ ๋๋งํ๋ ๋์ setState๋ฅผ ์ฌ์ฉํ๋ฉด ์ ๋ฉ๋๋ค. ์์ ์ ํญ์ ์ด๊ฒ์ ๋ํด ๊ฒฝ๊ณ ํ์ต๋๋ค.
ํด๋น ํจ์ ๊ตฌ์ฑ ์์ ๋ณธ๋ฌธ์ ๋ณธ์ง์ ์ผ๋ก ํด๋์ค ๊ตฌ์ฑ ์์ ๋ ๋๋ง ๋ฉ์๋์ ๋์ผํฉ๋๋ค.
ํจ์ ๊ตฌ์ฑ ์์ ๋ณธ๋ฌธ ์ค์ ๋ค๋ฅธ ๊ตฌ์ฑ ์์์ ๋ํ setState๊ฐ ์ด์ ์ ๊ฒฝ๊ณ ํ์ง ์์ ๊ฒ์ ์ค์ ๋ก ์ฐ๋ฆฌ์ ๋๋ฝ์ ๋๋ค. ๋น์ ์ ์์ ๋ ์ ์์ ๋์ ํจํด์ ๋๋ค ์ถ๋ก ํ ์ ์์ง๋ง, ํ๋๋ ๊ทธ๊ฒ์ ์คํํ์ง ๋ชปํ์ต๋๋ค ๋งํ ๊ณต์ ์ด๋ค. ๋ถํธ์ ๋๋ ค ์ฃ์กํฉ๋๋ค.
๋ฌธ์์์ ์ด๋ฅผ ์ธ๊ธํด์ผ ํ๋ ํน์ ์์น๊ฐ ์๋ค๊ณ ์๊ฐ๋๋ฉด ๋ฌธ์ ์ ์ฅ์์ ๋ฌธ์ ๋ฅผ ์ ๊ธฐํ์ธ์. Hooks๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ฌธ์๋ฅผ ๋ค์ ์์ฑํ ๊ณํ์ด๋ฏ๋ก ์ผ๋์ ๋ ์ ์์ต๋๋ค. ๊ฐ์ฌ ํด์!
๋๋ ๊ฒฐ์ฝ ๋๊ตฐ๊ฐ๋ฅผ ๊ธฐ๋ถ ๋์๊ฒ ๋ง๋ค ์๊ฐ์ด ์์ผ๋ฉฐ, ๋๋ ๋น์ ์ ์ฌ๊ณผ๋ฅผ ๋ฐ์๋ค์ด๊ธฐ๋ฅผ ๊ฑฐ๋ถํฉ๋๋ค ;) ํํฌ๋ ์ฒ์ฌ์ด๋ฉฐ, ์ฌ๋ฌ๋ถ์ ํํฌ๋ฅผ ๋ฐ๋ช ํ ์ฒ์ฌ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ชจ๋ ๊ฒฐ๊ณผ๋ฅผ ์๋ฒฝํ๊ฒ ์์ํ์ง ๋ชปํ๋ค๊ณ ๋ค๋ฅธ ์์ง๋์ด๋ฅผ ํํ๋ ์์ง๋์ด๋ ... ๋ฐ๋ณด์ ๋๋ค.
๋ด๊ฐ ์์ฌ์ํต์ ํ๋ ค๊ณ ํ๋ ๊ฒ์ ํ์ฌ ์ด ๊ฒฝ๊ณ ๋ฅผ ๋ฐ์์ ๋ ๋ชจ๋ ์ฌ๋๋ค์ด ํ๋ ๋๋ก ํ๋ค๋ ๊ฒ์ ๋๋ค. ๊ตฌ๊ธ๋ง์ ํด๋ดค์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ "์ด ์๋ก์ด ๊ฒฝ๊ณ ๊ฐ ์์ต๋๋ค"๋ผ๋ ํ์ด์ง๋ฅผ ์ฐพ์์ต๋๋ค.
๋๋ ๋จ์ง ๊ทธ ๋ฐํ์ ๋งํฌ๊ฐ ์๊ฑฐ๋ ๊ตฌ๊ธ๋ง์ ํตํด ๋๊ตฐ๊ฐ๊ฐ ์ฐพ์ ์ ์๋ ์ ์ฌํ ์ฅ์์ "์ฌ๊ธฐ์ ์๋ ์ฐ๋ฆฌ๊ฐ ์ด ์ค๋ฅ๋ฅผ ๋์ ํ ์ด์ ์ ๋ฉ์ง React ๊ฐ๋ฐ์๊ฐ ๋ ์ ์๋ ๋ฐฉ๋ฒ๊ณผ ์ง์ ๋ฐ์ํ์ง ์๋๋ก ๋ช ๊ฐ์ง ๊ธฐ๋ณธ ์ง์นจ์ ๋ฐ๋ฅด๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค."
๊ทธ๋ฌ๋ ๋ค์, hooks๋ ๊ต์ฅํ๊ณ React ํ์ ๊ต์ฅํ๋ฉฐ ์ด ์๋ก์ด ๊ฒฝ๊ณ ์กฐ์ฐจ๋ ๊ต์ฅํฉ๋๋ค(๋ณดํธํ๋ ค๋ ์ค๋ฅ๋ฅผ ๋ฐ๊ฒฌํ๋ ๋ฐ ์ง์ฅ์ ๋ฅ๊ฐํ ๊ฒ์ด๋ผ๊ณ ํ์ ํฉ๋๋ค). ๋๊ตฐ๊ฐ์๊ฒ ์ฌ๊ณผ๋ฅผ ๋น์ง ์ฌ๋์ด ์๋ค๋ฉด ๋ด๊ฐ ์ฑ ์์ ์ ธ์ผ ํฉ๋๋ค.
๋ฌผ๋ก ํ๋ ๊ฐ์ ์ ์์ต๋๋ค. "์"์ ๋ํ ๋๋ต์ "๋ ๋๋ง ์ค์ ํ ๊ตฌ์ฑ ์์๊ฐ ๋ค๋ฅธ ๊ตฌ์ฑ ์์์ ๋ํ ์ ๋ฐ์ดํธ๋ฅผ ํธ๋ฆฌ๊ฑฐํ๋ฉด ๋ ์ด์ ์์์ ์๋๋ก ์ด๋ํ์ง ์๊ธฐ ๋๋ฌธ์ ์ฑ์ ๋ฐ์ดํฐ ํ๋ฆ์ ์ถ์ ํ๊ธฐ๊ฐ ๋งค์ฐ ์ด๋ ค์์ง๋๋ค"๋ณด๋ค ๋ ๋ณต์กํ์ง ์์ต๋๋ค. ๋ฐ๋ผ์ ๊ทธ๋ ๊ฒ ํ๋ฉด React์ ์ด์ ์ ๋ฒ๋ฆฌ๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค.
๋ค์ ํ ๋ฒ ๋ช ํํ ํ์๋ฉด, ์ด๊ฒ์ ๊ทธ ์์ฒด๋ก ์๋ก์ด ๊ฒ์ด ์๋๋๋ค. ํด๋์ค์๋ ํญ์ ๋์ผํ ๊ฒฝ๊ณ ๊ฐ ์์์ต๋๋ค. ์ฐ๋ฆฌ๋ Hooks๋ก ๊ทธ๊ฒ์ ๋์ณค๊ณ , ๊ทธ ์ค์๋ฅผ ์์ ํ๊ณ ์์ต๋๋ค. ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์ฌ๋ก์ ๋ฐ๋ผ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ์ ํํ ์ง์นจ์ ๋๋ฆด ์๋ ์์ง๋ง ์ด๋ ค์์ ๊ฒช๊ณ ์๋ ์๋ฅผ ๊ณต์ ํด ์ฃผ์๋ฉด ๊ธฐ๊บผ์ด ๋์๋๋ฆฌ๊ฒ ์ต๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ํญ์ ์กด์ฌํ๋ ํด๋น ํด๋์ค ๊ฒฝ๊ณ ๋ฅผ ์์ ํ๋ ๊ฒ๊ณผ ์ ์ฌํ ๋ฐฉ์์ผ๋ก ์์ ํฉ๋๋ค.
์กฐ๊ธ์ด๋๋ง ๋์์ด ๋๊ธธ ๋ฐ๋๋๋ค!
๋๋ ์ด ํ ๋ก ์ 2์ผํธ๋ฅผ ์ถ๊ฐํ๊ณ ๊ธฐ๋ฅ ๊ตฌ์ฑ ์์์ ํํฌ๊ฐ ๋์ ๋ ์ดํ๋ก ๋ง์ ํผ๋์ด ์์๋ค๋ @machineghost์ ์๊ฒฌ์ ๋์ํฉ๋๋ค. ์ปค๋ฎค๋ํฐ์์๋ ๋ฆฌ์กํธํ์ ๋ฆฌ๋์ญ์ผ๋ก ์ฐพ๊ณ ์๋๋ฐ, ์์ ์๋ ๋จ์ํ๋ ๊ฒ๋ค์ด ์ ์ ๋ณต์กํด์ง๊ณ ์ํต๊ณผ ๋ช ํํ ์ฌ๋ก๊ฐ ๋ถ์กฑํ ๊ฒ ๊ฐ์ต๋๋ค.
์ผ์ด์ค์ ํฌ์ธํธ๋ ComponentDidMount ๋ฐ Unmount์ ๋๋ค. ๋จผ์ ํจ์ ๊ตฌ์ฑ ์์๋ฅผ ์ฌ์ฉํ๋ผ๋ ์ง์๋ฅผ ๋ฐ์ ๋ค์ ๋น ๋ฐฐ์ด๊ณผ ํจ๊ป useEffect๋ฅผ ์ฌ์ฉํ๋ผ๋ ์ง์๋ฅผ ๋ฐ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ด๊ฒ์ด ์ข์ง ์๋ค๋ ์ง์๋ฅผ ๋ฐ์์ต๋๋ค. ์ด์ ์ด ์ค๋ฅ ๋ฉ์์ง๊ฐ ์๋ง์ด ๋์์ต๋๋ค. ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ๋์ํ๋ ๋ชจ๋ ๋ ธ๋ ฅ์ ๊ฐ์ฌํ์ง๋ง ๋ฌธ์ํ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก์ ๋ ๋ง์ ๋ ธ๋ ฅ์ ๊ธฐ์ธ์ฌ์ผ ํฉ๋๋ค.
๋๋ ๋๋ฌด ์ค๋ซ๋์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ(ํ ์ด์ ์๋ Recompose ๋ฑ์ผ๋ก ํด๋์ค๋ฅผ ํผํ๋ ค๊ณ ์๋) ๊ทธ ํด๋์ค ๊ฒฝ๊ณ ์กฐ์ฐจ ๊ธฐ์ตํ์ง ๋ชปํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๊ทํ์ ์๋ต์ ๊ฐ์ฌํ์ง๋ง ์ ๋ ์ฃผ๋ก "๊ฒฝํ ๋ฒ์น", ์ง์นจ, ๋ชจ๋ฒ ์ฌ๋ก ๋ฑ์ ๊ธฐ๋ํ๊ณ ์์์ต๋๋ค. " ๋๋ "์ ์ด ํจํด์ ๋ฐ์ ์ ์ฌ์ฉํ์ฌ ์ํ ์ค์ ์๋ฅผ ํ์ ๊ตฌ์ฑ ์์๋ก ์ ๋ฌํฉ๋๋ค."
์๋ง๋ ์ฌ๊ธฐ์๋ ์์ ์๋ ์์ง๋ง "๊ธฐ๋ฅ ๊ตฌ์ฑ ์์ A๊ฐ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ฉด ์ํ ์ค์ ์๋ฅผ ์ ๋ฌํ๋ ํ์ ๊ตฌ์ฑ ์์ B๋ฅผ ๋ ๋๋งํด์๋ ์ ๋ฉ๋๋ค. ์์ ๊ตฌ์ฑ ์์๊ฐ ๋ ๋๋ง๋๊ณ ์ํ๊ฐ ๋ณ๊ฒฝ๋๋ฉด ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค."
์๋๋ฉด ์ผ์์ผ์ด ๋ฆ์ด์ ํ๋ฃจ ์ข ์ผ ๊ฐ์ธ ํ๋ก์ ํธ์ ๋ชฐ๋ํ๊ณ , ๋ด ๋๋๋ ๋๋ฌด ํ์ด์ ๋จ์ํ ๊ฒ์ ์ด๋ ค์ด ๊ฒ์ผ๋ก ๋ง๋ค๊ณ ์์ต๋๋ค. ์ด๋ ์ชฝ์ด๋ , ์ง์นจ์ ๋ํ ์ถ๊ฐ ์ ์์ด ์์ผ๋ฉด ๋ค์ ๊ฒ์ํ ๊ฒ์ด์ง๋ง, ๊ทธ๋ ์ง ์์ผ๋ฉด ๋ค๋ฅธ ์ฌ๋์ด ์ด์ ๋ํด ์ผ์์ผ ๋ฐค์ ๋ณด๋ด๋ ๊ฒ์ ์ํ์ง ์์ต๋๋ค.
๊ทธ๋๋ ๋ค์ ํ ๋ฒ ๊ฐ์ฌํฉ๋๋ค!
๋๋ ์ฐ๋ฆฌ๊ฐ ์ด ์ฐ๋ ๋๊ฐ ๊ทธ ์ ์ฉ์ฑ์ ๋ฅ๊ฐํ๋ ์ง์ ์ ๋๋ฌํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ผ์ด์ค์ ํฌ์ธํธ๋ ComponentDidMount ๋ฐ Unmount์ ๋๋ค. ๋จผ์ ํจ์ ๊ตฌ์ฑ ์์๋ฅผ ์ฌ์ฉํ๋ผ๋ ์ง์๋ฅผ ๋ฐ์ ๋ค์ ๋น ๋ฐฐ์ด๊ณผ ํจ๊ป useEffect๋ฅผ ์ฌ์ฉํ๋ผ๋ ์ง์๋ฅผ ๋ฐ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ด๊ฒ์ด ์ข์ง ์๋ค๋ ์ง์๋ฅผ ๋ฐ์์ต๋๋ค. ์ด์ ์ด ์ค๋ฅ ๋ฉ์์ง๊ฐ ์๋ง์ด ๋์์ต๋๋ค.
์ ํฌ ๋ฌธ์๊ฐ ๋์์ด ๋์ง ๋ชปํด์ ์ ๊ฐ์ด์ง๋ง ์ด๋ค ํน์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋์ง ๋งํ๊ธฐ๋ ๋งค์ฐ ์ด๋ ต์ต๋๋ค. ์ด๊ฒ์ ๋ถํํ๋ ๋งค์ฐ ๋ชจํธํ๋ฉฐ ์ฐ๋ฆฌ๊ฐ ๋งํ๋ ค๊ณ ํ ๊ฒ์ ์๊ณก์ ๋๋ค. ๊ณ ์ฅ๋ ์ ํ๊ธฐ ๊ฒ์์ฒ๋ผ. ํน์ ๋ฌธ์ ๊ฐ ์๋ ๊ฒฝ์ฐ ์ ๋ฌธ์ ๋ฅผ ์ ์ถํ๊ณ ๋ ์์ธํ ์ค๋ช ํ์ญ์์ค. ์ข ๋ ๊ตฌ์ฒด์ ์ผ๋ก ์๋ ค์ฃผ์๋ฉด ๋์๋๋ฆฌ๊ฒ ์ต๋๋ค.
๊ทํ์ ์๋ต์ ๊ฐ์ฌํ์ง๋ง ์ ๋ ์ฃผ๋ก "๊ฒฝํ์ ๊ท์น", ์ง์นจ, ๋ชจ๋ฒ ์ฌ๋ก ๋ฑ์ ๊ธฐ๋ํ๊ณ ์์์ต๋๋ค.
๊ฒฝํ์ ๋ฒ์น์ ํญ์ "๋ ๋๋งํ๋ ๋์ ๋ถ์์ฉ์ ์ํํ์ง ๋ง์ญ์์ค"์์ต๋๋ค. ๋ ๋๋ง์ ์์ํ ๊ณ์ฐ์ผ๋ก ์๊ฐํ์ญ์์ค. ๋ถ์์ฉ์ ๋ค๋ฅธ ์์น๋ก ์ด๋ํฉ๋๋ค(ํด๋์ค์ ์๋ช ์ฃผ๊ธฐ ๋ฉ์๋ ๋๋ ํจ์ ๊ตฌ์ฑ ์์์ useEffect). ๊ทธ ์ด์์ ์์ต๋๋ค.
"๊ธฐ๋ฅ ๊ตฌ์ฑ ์์ A๊ฐ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ฉด ์ํ ์ค์ ์๋ฅผ ์ ๋ฌํ๋ ํ์ ๊ตฌ์ฑ ์์ B๋ฅผ ๋ ๋๋งํด์๋ ์ ๋ฉ๋๋ค(๊ทธ๋ ๋ฐ๋ก ๋ฐํํด์ผ ํจ). ์๋ํ๋ฉด ํ์ ๊ตฌ์ฑ ์์๊ฐ ์ํ๋ฅผ ๋ ๋๋งํ๊ณ ๋ณ๊ฒฝํ๋ฉด ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ๋๋ค."
์ฌ๊ธฐ์ ์์ง ์คํด๊ฐ ์๋ ๊ฒ ๊ฐ์์. ์ํ ์ค์ ์๋ฅผ ์์ ๊ตฌ์ฑ ์์์ ์ ๋ฌํ๋ ๊ฒ์ ์๋ฒฝํฉ๋๋ค. ํญ์ ๊ด์ฐฎ์๊ณ , ์์ผ๋ก๋ ๊ทธ๋ด ๊ฒ์ ๋๋ค.
๋ฌธ์ ๋ ๋ ๋๋งํ๋ ๋์ ํธ์ถํ๋ ๊ฒ ์ ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ์์ ํ ๋ถํ์ํด์ผ ํฉ๋๋ค. ๊ตฌ์ฒด์ ์ธ ์๊ฐ ์์ผ๋ฉด ์ ๊ทธ๋ฌ๋์ง ์ง์ํ๊ธฐ ์ด๋ ต์ต๋๋ค. ๊ทธ๋์ ๋์์ด ์ด๋ ต์ต๋๋ค.
์ด ๋ ๋ํ์ ์ผ๋ฐ์ ์ธ ์ฃผ์ ๋ ์ฐ๋ฆฌ๊ฐ ์์ ๊ทธ๋ฆฌ๋ฉฐ ๊ฐ๊ณ ์๋ค๋ ๊ฒ์ ๋๋ค. ํ ๋ก ์ ๋ฉํ๋ก ์ ํ๋์์ผ๋ฉฐ ํน์ ์ฌ๋ก์ ๋ํด ์ด์ผ๊ธฐํ๋ ๋์ ๋ชจํธํ ์ผ๋ฐ์ฑ์ ๋ํด ๋ ผ์ํ๊ณ ์์ต๋๋ค. ์๋ก ์คํดํ ๊ฐ๋ฅ์ฑ์ด ๋์ง๋ง ๊ตฌ์ฒด์ ์ธ ์ฌ๋ก๊ฐ ์๊ธฐ ๋๋ฌธ์ ์คํด๋ฅผ ํ๊ธฐ๊ฐ ๋ถ๊ฐ๋ฅํ๋ค.
์ด๋ฌํ ์ด์ ๋ก ์ด ์ค๋ ๋๋ฅผ ์ ๊ธ ๊ฒ์ ๋๋ค. ์ฌ๊ธฐ ๊ณ์ ๋ชจ๋ ๋ถ๋ค์ ์๊ฒฌ์ ์ง์ฌ์ผ๋ก ๊ฐ์ฌ๋๋ฆฝ๋๋ค. ์ด ๊ฒฝ๊ณ ๋ฅผ ์์ ํ๋ ๋ฐ ์ด๋ ค์์ ๊ฒช๊ณ ๊ณ์ ๋ค๋ฉด ๋ ๋ง์ ์ ๋ณด๋ฅผ ๋ฃ๊ณ ์ถ์ต๋๋ค. ๋์์ ๋ฐ๋ ๋ฐฉ๋ฒ์ ์ต์ํ์ ์ฌํ ์ฌ๋ก๋ก ๋ฌธ์ ๋ฅผ ์ ๊ธฐํ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๊ตฌ์ฒด์ ์ธ ๋ฌธ์ ์ ๋ํด ๋ ผ์ํ๊ณ ์๋ฃจ์ ์ ๋ธ๋ ์ธ์คํ ๋ฐํ๋ ๋ฐ ๋์์ ๋๋ฆด ์ ์์ต๋๋ค. ์ด๊ฒ์ ๊ด๋ จ๋ ๋ชจ๋ ์ฌ๋์๊ฒ ๋ ์์ฐ์ ์ด๋ฉฐ, ์ด๋ฏธ ์ด ์ค๋ ๋์ ๋๊ธ์ ๋ฌ๊ณ ๊ตฌ๋ ์ ๋ง์น ์์ญ ๋ช ์ ์ฌ๋๋ค์๊ฒ ์ด๋ฉ์ผ์ ๋ณด๋ด๋ ๊ฒ์ ํผํ ๊ฒ์ ๋๋ค. ๊ฐ์ฌํฉ๋๋ค!
์์ ์ ๋ฐ์ดํธ๋ก(๋ชจ๋์๊ฒ ํ์ ๋ณด๋ด์ ์ฃ์กํฉ๋๋ค) https://github.com/final-form/react-final-form/issues/751#issuecomment -606212893์ ์ฌ์ฉํ๋ ์ฌ๋๋ค์ ์ํด ์ด๋ฌํ ์ค๋ฅ๋ฅผ ํด๊ฒฐํ๋ค๊ณ ๋ค์์ต๋๋ค. ๋์๊ด.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
๋ฏธ๋์ ๋๊ธ ์์ฑ์์๊ฒ. ์๋ก์ด ๊ฒฝ๊ณ ๊ฐ ํ์๋๋ ๊ฒ์ด ๋ต๋ตํ๋ค๋ ์ ์ ์ดํดํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ฝ๋์ ๋ฒ๊ทธ๋ฅผ ์ผ์ผํฌ ๊ฐ๋ฅ์ฑ์ด ์๋ ํฉ๋ฒ์ ์ธ ๋ฌธ์ ๋ฅผ ์ง์
์คํ ์ถ์ ์์ ์ถ์ฒ๋ฅผ ์ดํดํ ์ ์๋ ๊ฒฝ์ฐ ์คํฌ๋ฆฐ์ท์ ๊ฒ์ํ๊ฑฐ๋ ์ฌ์์ฐ ์๋๋ฐ์ค๋ฅผ ์์ฑํด ์ฃผ์๋ฉด ๋์๋๋ฆฌ๊ฒ ์ต๋๋ค. ๋๋ถ๋ถ์ ๋ช ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๊ฐ์ ธ์จ ๊ฒ์ผ ์ ์์ผ๋ฏ๋ก ๊ฐ์ฅ ์์ฐ์ ์ธ ๋ฐฉ๋ฒ์ ์ด๋ฌํ ๊ฒฝ์ฐ๋ฅผ ์ค์ด๊ณ ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ฌธ์ ๋ฅผ ์ ๊ธฐํ๋ ๊ฒ์ ๋๋ค.
๋ค๋ค ๊ฐ์ฌ ํด์.