π©βπ«λ¦¬μ‘νΈ Hooksμ μ’ λ₯λ€μ μ 리νκ³ μ€μ΅ λ μ¬μ©ν μλ€μ 볡μ΅νκ³ μ μμ±νλ€
const [state,setState] = useState(5);
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});
useEffect(()=>{
// μμ
}); // μΈμλ‘ νλμ μ½λ°±λ§ λ°μ, λ λλ§ λ λ λ§λ€ μ€ν
useEffect(()=>{
//μμ
},[value]) // μ½λ°±ν¨μμ λ°°μ΄(λνλμ μ΄λ μ΄),
// νλ©΄μ 첫 λ λλ§ λ λ μ€ν
// value κ°μ΄ λ°λ λ μ€ν
// [] (empty λ°°μ΄λ‘ λ£μ΄μ£Όλ©΄ νλ©΄ λ λλ§ μμλ§ μ€ν!)
μ»΄ν¬λνΈκ° UIμμ μ κ±°λ λ (unmount)λ λ μ 리λμ΄μΌ νλ λΆλΆ μ²λ¦¬νλ€
μ΄λ λ©λͺ¨λ¦¬ λμ(Memory Leak) λ°©μ§λ₯Ό μν΄ UI μμ μ»΄ν¬λνΈλ₯Ό μ κ±°νκΈ° μ§μ μ μν
λ€μ μ΄ννΈ ν¨μκ° μ€νλ λ λ§λ€ ν΄λ¦°μ ν¨μκ° λ¨Όμ μ€νλμ΄ μ 리 νλ€
return ν¨μ μμμ μ°λ¦¬κ° μνλ μμ μ ν΄μ£Όλ©΄λλ€
ν¨μλ₯Ό 리ν΄ν΄μ£Όλ©΄ ν΄λΉ μ»΄ν¬λνΈκ° μΈλ§μ΄νΈλ λ, λ€μ λ λλ§ μ λΆλ¦΄ useEffect κ° μ€νλκΈ° μ μ μ΄ ν¨μκ° μ€νλλ κ²μ΄λ€
useEffect(()=>{
//ꡬλ
return() =>{
// ꡬλ
ν΄μ§
} /* returnμ μ€κ΄νΈλ₯Ό ν΄μ§νμ§ μκ³ μ°λ κ²μ΄ κΆμ₯,
clean ν λ΄μ©μ μ΄ λΆλΆμ μμ±νλ©΄λ¨*/
},[]);
setInterval μ μ΄μ©ν μ€μ΅ μ§ν
export default function App() {
// μ»΄ν¬λνΈ μν
// [state,setState] = useState(???);
// 1.tuple data type = [state,setState]
//2. initial = static | Lazy
// const [appName, setAppName] = useState(props.appName);
React.useEffect(() => {
console.log(`change app name:${appName}`);
//μ¬μ΄λ μ΄ννΈ μ€μ
// νμ 컨νΈλ‘€ (React μ μν΄ κ΄λ¦¬λλ κ²μ΄ μλ: λΆμν¨κ³Ό )
// 3μ΄ λ§λ€ μ§μμ μΌλ‘ μ
λ°μ΄νΈλ₯Ό μ€ννλ €κ³ ν¨
const clearId = setInterval(() => setAppName((prevState) => prevState + `π€£`), 3000);
return (
() => {
clearInterval(clearId);
},
[appName]
);
/ }); // ꡬλ
λ³΄λ€ μ·¨μλ₯Ό λ¨Όμ νλ€ ,
const ref = useRef(value)
{current : value} /// μμ±νλ©΄ κ°μ²΄κ° μμ±λλ κ²μ΄λ€
μ μ₯곡κ°
- state μ λΉμ·ν μν λ‘ μ»΄ν¬λνΈμ μνλ₯Ό μ μ₯νλλ° state λ λ³νλ λ λ§λ€ λ λλ§μ΄ μ΄λ£¨μ΄μ§κ³ μ»΄ν¬λνΈμ λ΄λΆ λ³μλ€μ΄ μ΄κΈ°νλλ€
- μ΄λ¬ν λ¨μ μ΄ Ref μμ κ°μ μ μ₯ν΄μ£Όκ³ μ΄ κ°μ μ무리 λ³κ²½ν΄λ λ λλ§μ΄ μ΄λ£¨μ΄μ§μ§ μλλ€ β λ³μλ€μ κ°μ΄ μ μ§λλ€ !!
- λΆνμν λ λλ§μ μ μ§ν μ μλ κ²
- λ³κ²½ μ λ λλ§μ΄ μ΄λ£¨μ΄μ§μ§ μμμΌ νλ κ°λ€μ μ μ§νκΈ° μν΄μ μ μ©νλ€
/* eslint-disable indent */
import { useState, useRef } from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
const [count, setCount] = useState(0);
const countRef = useRef(0);
const increaeRef = () => {
countRef.current += 1;
};
return (
<div>
<p>You clicked ref {countRef.current} times</p>
<p>You clicked state {count} times</p>
<button onClick={() => setCount(count + 1)}>state Click me</button>
<button onClick={increaeRef}>ref Click me</button>
</div>
);
}
export default App;
π ref click me λ²νΌμ ν΄λ¦ν΄λ νλ©΄μ λ³νλ κ³μ 0 μ΄λ€κ° state λ₯Ό λ³κ²½νμ¬ λ λλ§λλ©΄ κ·Έμ μμΌ μΉ΄μ΄νΈ λμλ λ§νΌ νλ©΄μ κΈ°λ‘λλ κ²μ νμΈνλ€
Dom μμμ μ κ·Ό
/* eslint-disable indent */
import { useState, useRef, useEffect } from 'react';
import logo from './logo.svg';
import './App.css';
// const Div = (props) => <div {...props} />;
function App() {
const [name, setname] = useState('νκΈΈλ');
const countRef = useRef();
useEffect(() => {
countRef.current.focus();
});
const increaeRef = () => {
countRef.current += 1;
};
return (
<div>
<input type="text" ref={countRef}></input>
<p>{name}</p> //
<button onClick={() => setname(countRef.current.value)}>state Click me</button>
</div>
);
}
export default App;
π useEffect μ μ¬μ©νμ¬ λ λλ§ μ§νμ input νκ·Έμ focus κ° κ°λλ‘ ref λ₯Ό ν΅ν΄ μ€μ
π ref λ‘ μΈν΄ input μ value κ°μ κ°μ Έμμ μ΄λ²€νΈ ν΄λ¦μ state κ° λ³κ²½λ κ°λ₯
const value = useMemo(()=>{
return calculate();
},[item])
/* eslint-disable indent */
import { useState, useMemo, useEffect } from 'react';
import logo from './logo.svg';
import './App.css';
// const Div = (props) => <div {...props} />;
function App() {
const [num, setnum] = useState(0);
const [check, setCheck] = useState(false);
const todo = {
checked: check ? 'μλ£' : 'λΉμλ£',
title: ' react 볡μ΅νκΈ°',
content: 'hook λ°°μ΄κ±° notion μ μ 리νκΈ°',
};
useEffect(() => {
console.log('useEffectνΈμΆ');
}, [todo]);
return (
<div>
<input
type="checkbox"
checked={check}
onClick={() => {
setCheck(!check);
}}
></input>
<p>μν μ¬λΆ {todo.checked}</p>
<p>title:{todo.title}</p>
<p>content:{todo.content}</p>
<hr />
<input
type="number"
value={num}
onChange={(e) => {
setnum(e.target.value);
}}
/>
</div>
);
}
export default App;
π μ΄μκ°μ μν©μ useeffect λ‘ todo λ§ κ±Έμ΄λ¨μμλ number input μ λ³κ²½ν΄λ λ λλ§μ΄ κ³μ λ°μνλ€
π€·ββοΈ?? μ??
μ΄λ¬ν μν©μμ usememo κ° λ§€μ° λΉμ λ³΄λ€ !!
/* eslint-disable indent */
import { useState, useMemo, useEffect } from 'react';
import logo from './logo.svg';
import './App.css';
// const Div = (props) => <div {...props} />;
function App() {
const [num, setnum] = useState(0);
const [check, setCheck] = useState(false);
// const todo = {
// checked: check ? 'μλ£' : 'λΉμλ£',
// title: ' react 볡μ΅νκΈ°',
// content: 'hook λ°°μ΄κ±° notion μ μ 리νκΈ°',
// };
const todo = useMemo(
() => ({
checked: check ? 'μλ£' : 'λΉμλ£',
title: ' react 볡μ΅νκΈ°',
content: 'hook λ°°μ΄κ±° notion μ μ 리νκΈ°',
}),
[check]
);
useEffect(() => {
console.log('useEffectνΈμΆ');
}, [todo]);
return (
<div>
<input
type="checkbox"
checked={check}
onClick={() => {
setCheck(!check);
}}
></input>
<p>μν μ¬λΆ {todo.checked}</p>
<p>title:{todo.title}</p>
<p>content:{todo.content}</p>
<hr />
<input
type="number"
value={num}
onChange={(e) => {
setnum(e.target.value);
}}
/>
</div>
);
}
export default App;
πμ΄λ κ²νλ©΄ number input μ λ³κ²½ν λλ check κ°μ΄ λ³κ²½λμ§ μμλ€λ©΄ μ΄μ μ κ°μ κ·Έλλ‘ κ°μ Έμ€λ κ²μ νμΈνλ€!!
const calculate = useCallback((num)=>{
return num+1;
},[item])
useCallback() μ΄ νμν μμ
App.jsx
/* eslint-disable indent */
import { useState, useMemo, useEffect } from 'react';
import { Box } from './stateless/Box';
import logo from './logo.svg';
import './App.css';
// const Div = (props) => <div {...props} />;
function App() {
const [size, setSize] = useState(100);
const [theme, setTheme] = useState(true);
const createBoxStyle = () => {
return <{
backgroundColor: 'red',
width: `${size}px`,
height: `${size}px`,
};
};
useEffect(() => {
console.log('useEffectνΈμΆ');
}, []);
return (
<div style={{ background: theme ? 'white' : 'black' }}>
<input
type="number"
value={size}
onChange={(e) => {
setSize(e.target.value);
}}
/>
<Box createStyle={createBoxStyle}></Box>
<button
onClick={() => {
setTheme(!theme);
}}
>
ν
λ§λ₯Ό λ°κΎΈλ λ²νΌ
</button>
</div>
);
}
export default App;
Box.jsx
import { useState, useEffect } from 'react';
export function Box({ createStyle }) {
const [style, setStyle] = useState({});
useEffect(() => {
console.log('λ°μ€λ₯Ό ν€μ°κΈ° μν μ€νμΌ μμ');
setStyle(createStyle);
}, [createStyle]);
return <div style={style}></div>;
}
π ν λ§λ₯Ό λ°κΎΈλ λ²νΌμ λλ₯Ό μμ λ κ³μ ν¨μκ° μμ±μ΄ λκ³ , μλ‘μ΄ λ©λͺ¨λ¦¬ μ£Όμκ° ν λΉλλ©΄μ κ°μ΄ λ°λκ³ μλ€
β μ΄μ²λΌ λ°μ€μ μ¬μ΄μ¦κ° λ³κ²½λμ§ μμμλ μ§μμ λ λλ§μ΄ ν¨κ» μ΄λ£¨μ΄μ§λ κ²μ λΆνμν κΈ°λ₯μ΄κΈ°μ μ΄λ₯Ό useCallback μΌλ‘ λ§μμ£Όμ !!
λ³κ²½ ν
.App.jsx
/* eslint-disable indent */
import { useState, useMemo, useEffect, useCallback } from 'react';
import { Box } from './stateless/Box';
import logo from './logo.svg';
import './App.css';
// const Div = (props) => <div {...props} />;
function App() {
const [size, setSize] = useState(100);
const [theme, setTheme] = useState(true);
const createBoxStyle = useCallback(() => {
return {
backgroundColor: 'red',
width: `${size}px`,
height: `${size}px`,
};
}, [size]);
useEffect(() => {
console.log('useEffectνΈμΆ');
}, []);
return (
<div style={{ background: theme ? 'white' : 'black' }}>
<input
type="number"
value={size}
onChange={(e) => {
setSize(e.target.value);
}}
/>
<Box createStyle={createBoxStyle}></Box>
<button
onClick={() => {
setTheme(!theme);
}}
>
ν
λ§λ₯Ό λ°κΎΈλ λ²νΌ
</button>
</div>
);
}
export default App;
π ν λ§λ₯Ό λ°κΎΈλ λ²νΌμ μ¬λ¬λ² λμνμ¬λ Box.jsx μ useEffect μ μ€μ ν΄ λμ βλ°μ€λ₯Ό ν€μ°κΈ° μν μ€νμΌ μμβ μ΄λΌλ λ©νΈκ° 보μ΄μ§μλλ€
μ΄λ°μμ λΆνΌμν λ λλ§μ μ€μ¬λ³΄μ~
κΈ°μ‘΄μλ Context.Consumer + Render Props ν¨ν΄ or κ³ μ°¨μ»΄ν¬λνΈ(HOC) ν¨ν΄μ μ¬μ©νμ¬ λ¬Έμ ν΄κ²°
const cartContext = useContext(CarContext);
리μ‘νΈλ‘ λ§λ μ±μ μ¬λ¬κ°μ μ»΄ν¬λνΈλ‘ λ§λ€μ΄μ Έ μλ€. (λλ΅ μ΄λ° λͺ¨μμ νν)
μ΅μμ μ±μμ νΈλ¦¬ ννλ‘ (μμμ μλλ‘ prop λ₯Ό ν΅ν΄μ λ°μ΄ν°κ° μ λ¬λλ€)
λΆλͺ¨ μ»΄ν¬λνΈκ° μμ μ»΄ν¬λνΈ νκ·Έμ μΌμΌν prop νκ·Έλ₯Ό λ£μ΄μ μ λ¬νλ νν
μ μμ μΌλ‘ μ°λ λ°μ΄ν°λ€ ex ) user, theme , Language λ±
μ΄λ° μ μμ μΈ λ°μ΄ν°λ€κΉμ§λ μΌμΌν μ λ¬νλ€λ©΄ λ°λ³΅μ μΈ λ λλ§μ΄ νκ³ νκ³ ...μ€μ²©μ ννκ° λ°μν κ² (λ¨κ³ λ³λ‘ μ λ¬νλ€λ©΄ κ³ ν΅μ€λ¬μ, λ νλ λ°λλ©΄ μ»΄ν¬λνΈ μ°Ύμ λ€λλ©°μ λ°κΏμΌνλ€)
μ΄λ° ννλ₯Ό prop Drilling μ΄λΌκ³ νλ€
β λ κ·Έλ μ§ μμ context λ§μ μ¬μ©νλ€λ©΄ μλμ κ°μ λ¬Έμ μ λ°μ
1 ) Context λ₯Ό μ¬μ©νλ©΄ μ»΄ν¬λνΈλ₯Ό μ¬μ¬μ©νκΈ° μ΄λ €μμ§ μ μλ€
2 ) Prop drilling μ νΌνκΈ° μν λͺ©μ μ΄λΌλ©΄ Component Composition (μ»΄ν¬λνΈ ν©μ±) μ λ¨Όμ κ³ λ € ν΄λ³΄μ
π‘ context μ vlaue λ³κ²½μ΄ μ¦λ€λ©΄?β μμ£Ό λ³κ²½λμ§ μμ 컨ν μ€νΈλ₯Ό λΆλ¦¬ν΄μ λ³λ κ΄λ¦¬νκΈ° , μ»΄ν¬λνΈλ₯Ό λλ ν μμ£Ό λ³κ²½λμ§ μλ μ»΄ν¬λνΈλ useMemo λ₯Ό μ¬μ©νμ¬ propsκ° λ³κ²½λμ§ μμ κ²½μ° λ€μ λ λλ§ νμ§ μλλ‘ μμ±νλκ²μ΄ μ±λ₯ μ΄μλ₯Ό ν΄κ²°ν μ μλ€
// ν
λ§ μ»¨ν
μ€νΈ μμ±νκΈ° (ν
λ§ : μ½κΈ° μ μ© )
// ν
λ§ μ»¨ν
μ€νΈ κ°μ μμ± κ³Όμ μμ 곡κΈνκΈ°
// ν
λ§ μ»¨ν
μ€νΈ κ°μ λ°ννλ 컀μ€ν
ν
λ§λ€μ΄ λ΄λ³΄λ΄κΈ°
// ν
λ§ κ°μ λ°νμ(μ€ν) μ€μ λ³κ²½λμ§ μλ κ°μ΄λ―λ‘ κ·Έ κ°μ κΈ°μ΅ν΄λλ κ²μ΄ μ’λ€ .
import * as React from 'react';
const defaultTheme = {
light: {
background: '#f3f3f3',
color: '#191919',
accent: '#0d71f4',
},
dark: {
background: '#131313',
color: '#f9f9f9',
accent: '#f40d66',
},
};
const ThemeContext = React.createContext(defaultTheme);
// μ»΄ν¬λνΈ μ»¨ν
μ€νΈ κ°μ λ°ννλ ν¨μλ₯Ό μμ±
export const useTheme = () => {
const theme = React.useContext(ThemeContext);
if (!theme) {
throw new Error('ThemeContext μμμλ§ μ¬μ© κ°λ₯νλκΉ νμΈν΄ ');
}
return React.useMemo(() => theme, [theme]);
};
const [state, dispatch] = useReducer(reducer,initialState,initialZation)
const initialSinario = [
{ id: 'lkfs-fjkld-jflkxf', content: 'λ§λΈ μΊλ¦ν° μΆ©λ' },
{ id: 'kdfd-wkdif-kclskw', content: 'DC μΊλ¦ν° λμ€ νν°' },
];
const sinarioReducer = (state, action) => {
if (action.type === 'ADD_TEXT') {
console.log('ADD_TEXT μμ² μλ½');
}
if (action.type === 'EDIT_TEXT') {
console.log('EDIT_TEXT μμ² μλ½');
}
if (action.type === 'DELETE_TEXT') {
console.log('DELETE_TEXT μμ² μλ½');
console.log(action.payload);
return state.filter((text) => text.id !== action.payload);
}
return state;
};
/* μ‘μ
: μν μ
λ°μ΄νΈ μμ²μ */ {
type: 'DELETE_TEXT',
payload: deleteId,
}
dispatch(ACTION_A);
const initialization = () => {
// κ³μ°μ΄ νμν λ‘μ§
return { ... };
};