์ด ๊ธ์ udemy์ React ์๋ฒฝ ๊ฐ์ด๋ with Redux, Next.js, TypeScript ๊ฐ์ข๋ฅผ ๋ฐํ์ผ๋ก ์ ๋ฆฌํ ๋ด์ฉ์ ๋๋ค.
117. ๋ชจ๋ ์๊ฐ
- Effects, ReducersContext
- Working with (Side) Effects
- MAnaging more Complex State with Reducers
- Managing App - Wide or Component - Wide State with Context
118. "Side Effects"์ด๋ ๋ฌด์์ด๋ฉฐ useEffect๋ฅผ ์๊ฐํฉ๋๋ค.
- Main Job : Render UI & React to User Input
- Evaluate & Render JSX Manage State & Props React to (User) Events & Input Re-evaluate Component upon State & Prop Changes
- This all is "backed into" React via the "tools" and features covered in in this course (i.e. useState() Hook, Props ect).
- Side Effects: Anything Else
- Store Data in Browser Storage Send Http Requests to Backend Servers Set & MAnage Times
- These tasks must happen outside of the normal component evaluation and render cycle - especially since they might block/ delay rendering (e.g. Http requests)
Handling Side Effects with the useEffect() Hook
useEffect(() => { ... }, [ dependencies ]};
- first parameter : A function that should be executed AFTER every component evaluation IF the specified dependencies changed. Your side effect code goes into this function.
- second parameter : Dependencies of this effect-the function only runs if the dependencies changed. Specify your dependencies of your function here.
119. useEffect() ํ ์ฌ์ฉํ๊ธฐ
- local storage ํ์ฉ
- useEffect๋ side effects ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์กด์ฌํ๋ค. side effects๋ ๋ณดํต http request ๋ฑ์ด๋ค. ์ด๋ฉ์ผ ๋๋ ๋น๋ฐ๋ฒํธ ํ๋์ ํค ์ ๋ ฅ์ ๋ํ ์๋ต์ผ๋ก ํด๋น form์ ์ ํจ์ฑ์ ํ์ธํ๊ณ ์ ๋ฐ์ดํธ ํ๋ ๊ฒ ๋ํ side effect ๋ผ๊ณ ํ ์ ์๋ค. (์ด๋ ์ฌ์ฉ์ ์ ๋ ฅ ๋ฐ์ดํฐ์ side effect๋ผ๊ณ ํ ์ ์์)
- ๋ฌด์ธ๊ฐ์ ๋ํ ์๋ต์ผ๋ก ์คํ๋๋ ์ฝ๋๋ฅผ ๋ค๋ฃจ๋ ๋ฐ ์ค์ํ๋ค. ๋ฌด์ธ๊ฐ๋ ๋ก๋๋๋ ์ปดํฌ๋ํธ์ผ ์๋ ์๊ณ , ์ ๋ฐ์ดํธ ๋๋ ์ด๋ฉ์ผ ์ฃผ์์ผ ์๋ ์๋ค. ์ด๋ค ์ก์ ์ ๋ํ ์๋ต์ผ๋ก ์คํ๋๋ ์ก์ ์ด ์๋ค๋ฉด side effects ์ด๋ค.
useEffect(() => {
const storedUserLoggedInInformation = localStorage.getItem("isLoggedIn");
if (storedUserLoggedInInformation === "1") {
setIsLoggedIn(true);
}
}, []);
const loginHandler = (email, password) => {
localStorage.setItem("isLoggedIn", "1");
setIsLoggedIn(true);
};
const logoutHandler = () => {
localStorage.removeItem("isLoggedIn");
setIsLoggedIn(false);
};
121. ์ข ์์ฑ์ผ๋ก ์ถ๊ฐํ ํญ๋ชฉ ๋ฐ ์ถ๊ฐํ์ง ์์ ํญ๋ชฉ
- ์ํ ์ ๋ฐ์ดํธ ๊ธฐ๋ฅ
- "๋ด์ฅ" API or function
- ๋ณ์๋ ํจ์
122. useEffect์์ Cleanup ํจ์ ์ฌ์ฉํ๊ธฐ
- ๋๋ฐ์ด์ฑ, ์ฌ์ฉ์ ์ ๋ ฅ์ ๋๋ฐ์์(๊ทธ๋ฃนํ) ํ๊ธฐ
- (return) ์ต๋ช ํ์ดํ ํจ์๋ฅผ ๋ฐํํ๋๋ฐ, ์ด๋ฅผ ํด๋ฆฐ์ ํจ์๋ผ๊ณ ํ๋ค. useEffect๊ฐ ๋ค์ ๋ฒ์ ์ด function์ ์คํํ๊ธฐ ์ ์ clean up ํ๋ก์ธ์ค๋ก์จ ์คํ๋๋ค. ์ ํํ ๋งํ์๋ฉด useEffect ํจ์๊ฐ ์คํ๋๊ธฐ ์ (์ฒ์ ์คํ๋๋ ๊ฒฝ์ฐ๋ฅผ ์ ์ธํ๊ณ ) ์ด clean up ํจ์๊ฐ ์คํ๋๋ค. ๋ํ clean up ํจ์๋ effect๋ฅผ ํน์ ํ ์ปดํฌ๋ํธ๊ฐ DOM์์ mount ํด์ ๋ ๋๋ง๋ค ์คํ๋๋ค. (์ปดํฌ๋ํธ๊ฐ ์ฌ์ฌ์ฉ๋ ๋๋ง๋ค)
useEffect(() => {
const identifier = setTimeout(() => {
console.log("Checking form validity");
setFormIsValid(
enteredEmail.includes("@") && enteredPassword.trim().length > 6
);
}, 500);
return () => {
console.log("CLEANUP");
clearTimeout(identifier);
};
}, [enteredEmail, enteredPassword]);
→ ์ฒ์ ๋ก๋ ๋๋ฉด "Checking form validity" ์ด ํ์๋๋ค. ์ฌ๊ธฐ์ ๋ญ๊ฐ๋ฅผ ํ์ดํํ๋ฉด, "cleanup" ์ด ๋๊ณ , ๋ค์ "Checking form validity" ๊ฐ ํ์๋๋ค. ์ฌ๊ธฐ์ ๋ญ๊ฐ๋ฅผ ๋ ๋นจ๋ฆฌ ํ์ดํ ํ๋ฉด "cleanup"์ด ๋ง์ด ๋ณด์ธ๋ค. ํ์ง๋ง "Checking form validity" ์ ํ๋ฒ๋ง ํ์๋๋ค. ์ฆ, ๋ชจ๋ ํค ์ ๋ ฅ์ ๋ํด์ ์ด ์ฝ๋๋ ํ๋ฒ๋ง ์คํ๋์๋ค๋ ๋ป์ด๋ค.
→ ๋ง์ฝ http request๋ฅผ ๋ณด๋ด๋ ์์ ์๋ค๋ฉด, ์์ญ๊ฐ๊ฐ ์๋ ํ๋ฒ๋ง ๋ณด๋์ ๊ฒ.
123. useEffect ์์ฝ
- useEffect besides useState is the most important React hook you have.
Basic
useEffect(() => {
console.log("EFFECT RUNNING");
});
→ effec function runs after every component render cycle. Not before it and not during it, but after it.
array []
useEffect(() => {
console.log("EFFECT RUNNING");
}, []);
→ This function only executes for the first time this component was mounted and rendered, but not therafter, not for any subsequent rerender cycle
Use dependency
useEffect(() => {
console.log("EFFECT RUNNING");
}, [enteredPassword]);
→ ์ฒ์์ผ๋ก mount ๋์์ ๋ "EFFECT RUNNING" ์ด ์คํ๋๋ค. ์ด ๊ฒฝ์ฐ email input์ ํค๋ฅผ ์ ๋ ฅํด๋ ์๋ฌด๊ฒ๋ ๋ณ๊ฒฝ๋์ง ์์ง๋ง, password input์ key๋ฅผ ์ ๋ ฅํ๋ฉด "EFFECT RUNNING" ๊ฐ ํ์๋๋ค. password๋ dependency์ด๊ธฐ ๋๋ฌธ!
clean up function
useEffect(() => {
console.log("EFFECT RUNNING");
return () => {
console.log("EFFECT CLEANUP");
};
}, [enteredPassword]);
124. useReducers ๋ฐ Reducers ์ผ๋ฐ ์๊ฐ
- useReducer๋ ๋ด์ฅ๋ hook์ผ๋ก state ๊ด๋ฆฌ๋ฅผ ๋์์ค๋ค. ๊ทธ๋์ useState์ ์ฝ๊ฐ ์ ์ฌํ๋ค. ํ์ง๋ง ๋ ๋ง์ ๊ธฐ๋ฅ์ ๊ฐ๊ณ ์๋ค.
- ๋ ๋ณต์กํ state๋ฅผ ๊ด๋ฆฌํ ๋ ์ ์ฉํ๋ค. (e.g. ์ฌ๋ฌ state์ด ํจ๊ป ์ํด์๋ ๊ฒฝ์ฐ or ์ฌ๋ฌ state๊ฐ ๊ฐ์ด ๋ฐ๋๊ฑฐ๋ ์๋ก ๊ด๋ จ๋ ๊ฒฝ์ฐ์๋ useState๋ฅผ ์ด์ฉํ state๋ ์ข ์ข ์ฌ์ฉ ๋ฐ ๊ด๋ฆฌ๊ฐ ์ด๋ ค์ง ์ ์์)
- useReducer๋ useState๋ณด๋ค ์ฌ์ฉํ๊ธฐ๊ฐ ์กฐ๊ธ ๋ ๋ณต์กํด ์ค์ ์ด ๋ ํ์ํ๋ค. ๋๋ถ๋ถ์ ๊ฒฝ์ฐ์๋ useState๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ์ข์ง๋ง, useReducer์ ์ถ๊ฐ ์์ ์ ํ ๋งํ ๊ฐ์น๊ฐ ์๋ ๊ฒฝ์ฐ ์ฌ์ฉํ๋ฉด ์ข๋ค.
125. useReducer() hook ์ฌ์ฉ
const [state, dispatchFn] = useReducer(reducerFn, initialState, initFn);
- state : The state snapshot used in the component re-render/ re-evaluation cycle
- dispatchFn : A function that can be used to dispatch a new action (i.e. trigger an update of the state)
- reducerFn : (preveState, action) => newState / A function that is triggered automatically once an action is dispatched (via dispatchFn()) - it receives the latest state snapshot and should return the new, updated state.
- initialState. : The initial state
- initFn : A function to set the initial state programmatically
emailState๋ฅผ useReducer๋ก ๊ด๋ฆฌํด๋ณด๋๋ก ํ์.
const [emailState, dispatchEmail] = useReducer(emailReducer, {
value: "",
isValid: false,
});
const emailReducer = (state, action) => {
if (action.type === "USER_INPUT") {
return { value: action.val, isValid: action.val.includes("@") };
}
if (action.type === "INPUT_BLUR") {
return { value: state.value, isValid: state.value.includes("@") };
}
return { value: "", isValid: false };
};
reducer function์ ์ปดํฌ๋ํธ ํจ์ ๋ฐ๊นฅ์ ๋ง๋ค์๋ค๋ ๊ฒ์ ์ฃผ๋ชฉํ์. ๋ฆฌ๋์ ํจ์ ๋ด๋ถ์์๋ ์ปดํฌ๋ํธ ํจ์ ๋ด๋ถ์์ ๋ง๋ค์ด์ง ์ด๋ค ๋ฐ์ดํฐ๋ ํ์ํ์ง ์๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ผ์ ์ปดํฌ๋ํธ ํจ์์ ๋ฒ์ ๋ฐ์์ ๋ง๋ค์ด์ง ์ ์๋ค.
126. userReducer & useEffect
passwordState๋ฅผ useReducer๋ก ๊ด๋ฆฌํด๋ณด๋๋ก ํ์.
ํ์ง๋ง ์ด๋ ์ต์ ์ ์ฝ๋๊ฐ ์๋๋ค.
const [formIsValid, setFormIsValid] = useState(false);
์ฌ๊ธฐ์ ๋ ์ค์ํ ๊ฒ์ ํผ ์ ํจ์ฑ์ด๋ค. ์ ๋ ฅ์ ์ ์ฒด ํผ์ ์ผ๋ถ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
ex)
const emailChangeHandler = (event) => {
dispatchEmail({ type: "USER_INPUT", val: event.target.value });
setFormIsValid(event.target.value.includes("@") && passowrdState.isValid);
};
์ฌ์ ํ ํผ ์ ํจ์ฑ์ ๋ค๋ฅธ state์์ ๋์ถํ๊ธฐ ๋๋ฌธ์ด๋ค. ์ด๋ ๋ฆฌ์กํธ์ state ์ ๋ฐ์ดํธ Scheduling ๋๋ฌธ์ด๋ค.
๋ฆฌ์กํธ์ state ์ ๋ฐ์ดํธ Scheduling
๋ณํ์ง ์์ ์ด์ ์ state๋ฅผ ์ฐธ์กฐํ๊ฒ ๋ ์๋ ์๋ค. state๊ฐ useReducer์ setFormIsValid์์ ์ค๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ผ์ ์ด๋ ์ต์ ์ ์ฝ๋๋ ์๋๋ค. ๋ํ ๊ธฐ์ ์ ์ผ๋ก ํจ๊ป ์ํ๋ state๋ค์ด ๋ถํ๋ ๊ฒ์ ์ํ์ง ์์ ๊ฒ์ด๋ค. ๋ค์ ์ฃผ์ ์ฒ๋ฆฌ๋ฅผ ํ๊ณ , useEffect๋ฅผ ์ฌ์ฉํด๋ณด๋๋ก ํ์!
UseEffect ํด๊ฒฐ๋ฒ
const emailChangeHandler = (event) => {
dispatchEmail({ type: "USER_INPUT", val: event.target.value });
// setFormIsValid(event.target.value.includes("@") && passowrdState.isValid);
};
useEffect(() => {
const identifier = setTimeout(() => {
console.log("Checking form validity");
setFormIsValid(
emailState.isValid && passowrdState.isValid
);
}, 500);
return () => {
console.log("CLEANUP");
clearTimeout(identifier);
};
}, [emailState, passowrdState]);
→ useEffect ์์ ์๊ธฐ ๋๋ฌธ์ state๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค ํ์คํ ๋ค์ ์คํ๋๋ค. ์ต์ state ๊ฐ์ผ๋ก!
ํ๊ฐ์ง ๋ ๋ฌธ์ !
effect๊ฐ ๋๋ฌด ์์ฃผ ์คํ๋๊ณ ์๋ค. ์ด ์ฝ๋๋ emailState ๋ passwordState๊ฐ ๋ณํ ๋๋ง๋ค ์คํ๋๋ค. ๊ฐ๋ง ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ๋ ์์ ์๊ฐ ์๋ค. ์ด๋ฏธ input์ด ์ ํจํ๋ฐ, ๋น๋ฐ๋ฒํธ์ ๋ฌธ์๋ฅผ ์ถ๊ฐํ ๊ฒฝ์ฐ๋ผ๋ฉด ๋ฐ๋์ง ์๋๋ค. ๋ฌธ์๋ฅผ ์ถ๊ฐํ๊ธฐ ์ ์๋ ์ ํจํ๊ณ , ์ดํ์๋ ์ฌ์ ํ ์ ํจํ๋ค.
object de-structuring
const { isValid: emailIsValid } = emailState;
const { isValid: passwordIsValid } = passowordState;
useEffect(() => {
const identifier = setTimeout(() => {
console.log("Checking form validity");
setFormIsValid(emailIsValid && passwordIsValid);
}, 500);
return () => {
console.log("CLEANUP");
clearTimeout(identifier);
};
}, [emailIsValid, passwordIsValid]);
→ alias assignment ์ฌ์ฉํ๊ธฐ / de-structuring ๊ตฌ๋ฌธ ์ดํด๋ณด๊ธฐ
→ ๊น์ ํ ๋นํ๋ ๊ฒ์ ์๋, ๋ฑํธ์ ์ผ์ชฝ์์ ์ฌ์ฉํ๊ณ ์๊ธฐ ๋๋ฌธ / ๊ฐ์ฒด์์๋ ํด๋น ๊ฐ์ ์ถ์ถํ๊ธฐ ์ํด alias๋ฅผ ํ ๋นํ๋ค. (์์ฑ ์ถ์ถ์ ์ํด)
→ isValid ์์ฑ์ ๊บผ๋ด์ด ์์์ ์ ์ฅํ๊ณ , ๊ฐ๊ฐ ์ด๋ฆ์ ๋ถ์ฌ๋ณด๋๋ก ํ์. ์ด๋ฅผ alias assignment ๋ผ๊ณ ํ๋ค.
→ ๋น๋ฐ๋ฒํธ๊ฐ 6๊ธ์ ์ด์์ผ ๊ฒฝ์ฐ ๋์ด์ useEffect๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
127. ์ค์ฒฉ ์์ฑ์ useEffect์ ์ข ์์ฑ์ผ๋ก ์ถ๊ฐํ๊ธฐ
const { someProperty } = someObject;
useEffect(() => {
// code that only uses someProperty ...
}, [someProperty]);
useEffect()์ ๊ฐ์ฒด ์์ฑ์ dependencies์ผ๋ก ์ถ๊ฐํ๊ธฐ ์ํด destructuring์ ์ฌ์ฉํ๋ค. ์ด๋ ๋งค์ฐ general ํ ํจํด ์ ๊ทผ ๋ฐฉ์์ด๋ค. main point๋ destructuring์ ์ฌ์ฉํ๋ค๋ ๊ฒ์ด ์๋๋ผ, ์ ์ฒด ๊ฐ์ฒด ๋์ ํน์ ์์ฑ์ dependencies ์ผ๋ก ์ ๋ฌํ๋ค๋ ๊ฒ์ด๋ค.
useEffect(() => {
// code that only uses someProperty ...
}, [someObject.someProperty]);
๋ค์๊ณผ ๊ฐ์ด ์ฝ๋๋ฅผ ์์ฑํ์ฌ๋ ์๋ํ์ง๋ง, ์์ ๊ฐ์ ํจํด์ ํผํด์ผ ํ๋ค. effect ํจ์๋ someObject ๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค ์ฌ์คํ๋๊ธฐ ๋๋ฌธ์ด๋ค.
128. State ๊ด๋ฆฌ๋ฅผ ์ํธ useReducer vs useState
- Generally, you'll know when you need useReducer() : when using useState() becomes cumbersome or you're getting a lot of bugs / unintended behaviors)
useState()
- The main state management "tool"
- Great for independent pieces of state/data
- Greate if state updates are easy and limited to a few kinds of updates
useReducer()
- Greate if you need "more power"
- Should be considered if you have related pieces of state/data
- Can be helpful if you have more complex state updates
129. ๋ฆฌ์กํธ Context(Context API) ์๊ฐ
๋ก๊ทธ์ธ state๋ ์ฑ์ ๋ค์ํ ์์น์์ ํ์ํ๊ฑฐ๋ ์ฌ์ฉ๋๋ค. ์ด๊ฒ์ ์์ฃผ ๊ฐ๋จํ ์ฑ์ด๋ค. ์ฌ๊ธฐ์ state๋ฅผ ์ด๋ ๊ฒ ์ ๋ฌํด๋ ํฐ ๋ฌธ์ ๋ ๋์ง ์๋๋ค.
๋ฌธ์ ๊ฐ ๋๋ ๊ฒฝ์ฐ๋, state๋ฅผ ์ฌ๋ฌ ์ปดํฌ๋ํธ๋ฅผ ํตํด ์ ๋ฌํ๋ ๊ฒฝ์ฐ์ด๋ค. ์ฑ์ด ์ปค์ง์๋ก ์ด๋ ๊ฒ ํ๋ฉด ๋์ฑ ๋ถํธํด์ง๋ค. ์ด๋ ๊ฒ ํ๋ ๋์ props๋ฅผ ์ค์ ๋ก ํ์ํ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ชจ๋ก๋ถํฐ ๋ฐ๋ ์ปดํฌ๋ํธ์์๋ง ์ฌ์ฉํ ์ ์์ผ๋ฉด ๋ ์ข์ ๊ฒ์ด๋ค. ๋ถ๋ชจ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ์ง ์๋๋ก! ๋ถ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ์ง๋ ํ์ํ์ง๋ ์์.
์ปดํฌ๋ํธ ์ ์ฒด์์ ์ฌ์ฉํ ์ ์๋ ๋ฆฌ์กํธ์ ๋ด์ฅ๋/๋ด๋ถ์ ์ธ state ์ ์ฅ์๊ฐ ์๊ณ , ์ด๋ react context ๋ผ๋ ๊ฐ๋ ์ด๋ค. ์ด๋ฅผ ์ฌ์ฉํ๋ฉด ๊ธด porps ์ฒด์ธ์ ๋ง๋ค์ง ์๊ณ ๋, state๋ฅผ ๊ด๋ จ๋ ์ปดํฌ๋ํธ์ ์ง์ ์ ๋ฌํ ์ ์๋ค.
130. ๋ฆฌ์กํธ ์ปจํ ์คํธ API ์ฌ์ฉ
๋ฆฌ์กํธ ์ปจํ ์คํธ๋, ๋ฆฌ์กํธ ๋ด๋ถ์ ์ผ๋ก state๋ฅผ ๊ด๋ฆฌํ ์ ์๋๋ก ํด์ฃผ๋ ๊ฒ์ด๋ค. ์ฑ์ ์ด๋ค ์ปดํฌ๋ํธ์์๋ผ๋ ์ง์ ๋ณ๊ฒฝํ์ฌ ์ฑ์ ๋ค๋ฅธ ์ปดํฌ๋ํธ์ ์ง์ ์ ๋ฌํ ์ ์๊ฒ ํด์ค๋ค. (ํ๋กญ์ฒด์ธ ์์ด๋)
1. src/store ํด๋ ๋ง๋ค๊ธฐ
2. auth-context.js ํ์ผ ์ถ๊ฐ (์ผ๋ฐฅ ์ผ์ด์ค ์ฌ์ฉ)
provider
<AuthContext.Consumer></AuthContext.Consumer>
listener 2 way
1. Auth-Context consumer
<AuthContext.Consumer></AuthContext.Consumer>
→ the consumer is just one way of consuming our Context.
→ It's an okay-ish why, but i don't like that syntax too much
2. React Hook
import React, { useContext } from "react";
const ctx = useContext(AuthContext);โ
→ it is a bit more elegant and a bit nicer than using AuthContext Consumer
131. useContext ํ ์ผ๋ก ์ปจํ ์คํธ์ ํญํ(tapping)ํ๊ธฐ
const Navigation = (props) => {
const ctx = useContext(AuthContext);
return (
<nav className={classes.nav}>
<ul>
{ctx.isLoggedIn && (
<li>
<a href="/">Users</a>
</li>
)}
{ctx.isLoggedIn && (
<li>
<a href="/">Admin</a>
</li>
)}
{ctx.isLoggedIn && (
<li>
<button onClick={props.onLogout}>Logout</button>
</li>
)}
</ul>
</nav>
);
};
→ This is just a bit more elegant way in my opinion (teacher's opinion)
132. ์ปจํ ์คํธ๋ฅผ ๋์ ์ผ๋ก ๋ง๋ค๊ธฐ
return (
<AuthContext.Provider
value={{
isLoggedIn: isLoggedIn,
onLogout: logoutHandler,
}}
>
<MainHeader onLogout={logoutHandler} />
<main>
{!isLoggedIn && <Login onLogin={loginHandler} />}
{isLoggedIn && <Home onLogout={logoutHandler} />}
</main>
</AuthContext.Provider>
);
→ isLoggedIn์ ์ ๋ฌํ๋ ๊ฒ ์ธ์๋ ํจ์๋ฅผ ์ ๋ฌํ ์ ์๋ค. (๋ฌธ์์ด์ด๋ ๊ฐ์ฒด ๋ฑ์ ๊ฐ์ ์ ๋ฌํ ์ ์์)
→ props์ ๋์ด์ Navigation ์ปดํฌ๋ํธ์ ํ์ ์์ผ๋ฏ๋ก ์ ๊ฑฐํ ์ ์๋ค.
133. ์ฌ์ฉ์ ์ ์ ์ปจํ ์คํธ ์ ๊ณต์ ๊ตฌ์ฑ ์์ ๋น๋ ๋ฐ ์ฌ์ฉ
import React from "react";
const AuthContext = React.createContext({
isLoggedIn: false,
onLogout: () => {},
});
export default AuthContext;
→ IDE ์๋ ์์ฑ์ ๋ ์ข๊ฒ ๋ง๋ค๋ ค๋ฉด ๊ธฐ๋ณธ ์ปจํ ์คํธ ๊ฐ์ฒด์ onLogout์ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข๋ค. (๊ทธ๋ฅ ๋๋ฏธ ํจ์๋ก ๋ฃ์ด๋ ๋จ)
๋ณ๋์ ์ปจํ ์คํธ ๊ด๋ฆฌ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค๊ณ ์ถ๋ค๋ฉด?
# auth-context.js
import React, { useState, useEffect } from "react";
const AuthContext = React.createContext({
isLoggedIn: false,
onLogout: () => {},
onLogin: (email, password) => {},
});
export const AuthContextProvider = (props) => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(() => {
const storedUserLoggedInInformation = localStorage.getItem("isLoggedIn");
if (storedUserLoggedInInformation === "1") {
setIsLoggedIn(true);
}
}, []);
const logoutHandler = () => {
localStorage.removeItem("isLoggedIn");
setIsLoggedIn(false);
};
const loginHandler = () => {
localStorage.setItem("isLoggedIn", "1");
setIsLoggedIn(true);
};
return (
<AuthContext.Provider
value={{
isLoggedIn: isLoggedIn,
onLogout: logoutHandler,
onLogin: loginHandler,
}}
>
{props.children}
</AuthContext.Provider>
);
};
export default AuthContext;
# index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { AuthContextProvider } from "./store/auth-context";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<AuthContextProvider>
<App />
</AuthContextProvider>
);
App, Home, Login ์ปดํฌ๋ํธ์๋ ์ถ๊ฐ ์์ ์ ํด์ค๋ค.
const ctx = useContext(AuthContext);
์ฅ์
์ด๋ ๊ฒ ํ๋ ๊ฒ์ ์ฅ์ ์ ์ฑ ์ปดํฌ๋ํธ๊ฐ ๋ ๊ฐ๊ฒฐํด์ง๋ค๋ ๊ฒ์ด๋ค. state, authContext ๊ด๋ฆฌ๋ฅผ ๋ชจ๋ ํ๋์ ํ์ผ์์ ํ๋ค.
134. ๋ฆฌ์กํธ ์ปจํ ์คํธ ์ ํ (Context Limitations)
- React Context is Not optimized for highj frequency changes! (We'll explore a better tool for that, later)
- React Context also shouldn't be used to replace ALL component communications and props (Component should still be configurable via props and short "prop chains" might not need any replacement)
๋ณ๊ฒฝ์ด ์ฆ์ ๊ฒฝ์ฐ์, ๋ฆฌ์กํธ ์ปจํ ์คํธ๋ ๊ทธ๋ค์ง ์ ํฉํ์ง ์๋๋ค. ์ต์ ํ ๋์ด ์์ง ์๊ธฐ ๋๋ฌธ. (๊ณต์ ๋ฆฌ์กํธ ํ์๊ป์ ๋ง์ํ์ ๋ด์ฉ)
๋ ๋์ ๋๊ตฌ์ ๋ํด์๋ ๋์ค์ ์ด์ผ๊ธฐ ํ ์์ . ์ฐธ๊ณ ๋ก ๊ทธ ๋๊ตฌ ์ด๋ฆ์ ๋ฆฌ๋์ค(Redux)
135. "Hooks์ ๊ท์น" ๋ฐฐ์ฐ๊ธฐ โ
- Only call React Hooks in React Functions
- React Component Functions
- Custom Hooks (covered later!)
- Only call React Hooks at the Top Level
- Don't call them in nested functions
- Don't call them in any block statements
- +extra, unofficial Rule for useEffect(): Always add everything you refer to inside of useEffect() as a dependency!
136. ์ ๋ ฅ ์ปดํฌ๋ํธ ๋ฆฌํฉํ ๋ง
Login Component ์ ์๋ ์ค๋ณต๋ input (for id, password) ์ ํ๋์ ์ปดํฌ๋ํธ๋ก ๋ฆฌํฉํ ๋ง ํด๋ณด์!
const Input = (props) => {
return (
<div
className={`${classes.control} ${
props.isValid === false ? classes.invalid : ""
}`}
>
<label htmlFor={props.id}>{props.label}</label>
<input
type={props.type}
id="email"
value={props.value}
onChange={props.onChange}
onBlur={props.onBlur}
/>
</div>
);
};
export default Input;
137. Forword Refs'์ ๋ํด ์์๋ณด๊ธฐ โ
const submitHandler = (event) => {
event.preventDefault();
if (formIsValid) {
authCtx.onLogin(emailState.value, passowordState.value);
} else if (!emailIsValid) {
emailInputRef.current.activate();
} else {
passwordInputRef.current.activate();
}
};
→ ์๋ฌ ๋ฐ์
React.forwardRef / useImperativeHandler
- React.forwardRef ์ useImperativeHandler ๋ฅผ ํ์ฉํ์ฌ ํด๋น ์๋ฌ๋ฅผ ์ ๊ฑฐํ ์ ์๋ค.
138. ๋ชจ๋ ๋ฆฌ์์ค
- ๊ฐ์ ์์ค์ฝ๋ ์ฐธ๊ณ