
: 하나의 요청이 오면 완료가 된 후 다음 요청을 실행하는 방식
(순차적 로직흐름)
: 어떤 요청이 오면 완료가 되기 전에 다음 요청을 실행하는 방식
(동시 효율적 처리 가능, 즉시 응답X 때문에 예상 밖 결과 나올수도 있음)
const [ state, setState ] = useState(초기값)
ex. input의 value를 버튼 클릭 시 기본 배열에 추가하기 (깊은 복사)
useState의 인자값으로 콜백함수 활용하기
const heavyWork = () = > {
return ['a', 'b']
};
const [names, setNames] = useStrate(()) => {
return heavyWork(); // 콜백함수, 처음 렌더링 시에만 불려짐
};
const [input, setInput] =useState('');
const handleUpload = () => {
setNames((prevState) => {
return [input, ...prevState];
; };
}
! : true라면 false, false라면 true
const [showTimer, setShowTimer] = useState(false);
return (
<button onClick={() => setShowTimer(!showTimer) }></button>
)
useEffect(()=> {
// 작업
});
useEffect(()=> {
// 작업
}, [value]);
useEffect(()=> {
// 작업
}, []);
useEffect(() => {
const timer = setInterval(() => {
console.log("타이머 실행");
}, 1000);
return () => {
clearInterval(timer);
console.log("타이머 종료");
};
}, []);
useEffect 에서는 함수를 반환 할 수 있는데 이를 cleanup 함수라고 불린다.
useEffect(()=> {
// 구독
return () => {
// 구독해지
}
}, [value]);
setTimeout(( ) => console.log("2초 후에 실행됨"), 2000);
어떤 코드를 바로 실행하지 않고 일정 시간 기다린 후 실행하고 싶을 때 사용한다.
setTimeout() 함수는 첫번째 인자로 실행할 코드를 담고 있는 함수를 받고, 두번째 인자로 지연 시간을 밀리초(ms) 단위로 받는다.
const intervalId = setInterval(() => console.log(new Date()), 2000);
// Sun Dec 12 2021 12:45:31 GMT-0500 (Eastern Standard Time)
// Sun Dec 12 2021 12:45:33 GMT-0500 (Eastern Standard Time)
// Sun Dec 12 2021 12:45:35 GMT-0500 (Eastern Standard Time)
clearInterval(intervalId);
웹페이지의 특정 부분을 주기적으로 업데이트해줘야 하거나, 어떤 API로 부터 변경된 데이터를 주기적으로 받아와야 하는 경우에 사용한다.
첫번째 인자로 실행할 코드를 담고 있는 함수를 받고, 두번째 인자로 반복 주기를 밀리초(ms) 단위로 받는다.
clearInterval() 함수를 호출하면 코드가 주기적으로 실행되는 것을 중단시킬 수 있다.
const ref = useRef(value)
ref 오브젝트를 반환해준다.const countRef = useRef(0);
console.log(countRef); // { current: 0 }
console.log(countRef.current); // 0
countRef.current = countRef.current + 1;
💡 변화는 감지해야 하지만, 변화가 렌더링을 발생시키고 싶지 않을 때 사용한다.
const [count, setCount] = useState(0);
const renderCount = useRef(0);
useEffect(() => {
renderCount.current += 1;
console.log("렌더링 수: " + renderCount.current);
});
return (
<div>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
)
const ref = useRef(value)
<input ref={ref}/>
const { useEffect, useRef } from "react";
const App = () => {
const inputRef = useRef(); // {current:undefine}
useEffect(() => {
inputRef.current.focus();
}, []);
const login = () => {
alert(`환영합니다" ${inputRef.current.value}!`);
inputRef.current.focus();
}
return (
<div>
<input ref={inputRef} type="text" placeholder="username" /> // {current:input}
<button onClick={login}>Submit</button>
</div>
);
}
export default App;
<input ref={inputRef} type="text" placeholder="username" />
: 선택하고 싶은 DOM에 속성으로 ref 값을 설정해준다.
inputRef.current.focus();
: Ref 객체의 current 값은 우리가 선택하고자 하는 DOM을 가리킨다.
그리고 포커싱을 해주는 DOM API focus() 를 호출한다.
전역적인 데이터 전달이 편하다.
(pops의 경우 부모-자식 간의 상속 관계 필요)
전역적으로 데이터를 공유하기 때문에 중간 다리 역할만 하는 컴포넌트들을 건너뛰고 데이터가 필요한 컴포넌트에서 바로 사용이 가능하다.
Context를 사용하면 컴포넌트 재사용이 어려워 질 수 있다.
createContext 함수 import 후 상태관리를 할 값을 넣어주면 컨텍스트 객체 생성이 완료된다. // ThemeContext.js
import { createContext } from "react";
// null : 초기값
export const TheamContext = createContext(null);
createContext(null);
(null)은 Provider를 사용하지 않았을 때 적용될 초기값을 의미
<TheamContext.Provider>로 감싸준 모든 하위 컴포넌트들을 props가 없어도 value에 접근할 수 있다.Provider은 props로 value가 필요하다// App.js
import { useState } from "react";
import Page from "./components/Page";
import { TheamContext } from "./context/ThemeContext";
function App() {
const [isDark, setIsDark] = useState(false);
return (
<TheamContext.Provider value={{ isDark, setIsDark }}>
<Page />
</TheamContext.Provider>
);
}
export default App;
// Page.js
import React from "react";
import Context from "./Content";
import Footer from "./Footer";
import Header from "./Header";
const Page = () => {
return (
<div className="page">
<Header />
<Context />
<Footer />
</div>
);
};
export default Page;
useContext()의 인자로 만들어준 TheamContext 를 넣는다
import React, { useContext } from "react";
import { TheamContext } from "../context/ThemeContext";
const Footer = () => {
const { isDark, setIsDark } = useContext(TheamContext);
const toggleTheme = () => {
setIsDark(!isDark);
};
return (
<footer
className="footer"
style={{ backgroundColor: isDark ? "black" : "lightgray" }}
>
<button className="button" onClick={toggleTheme}>
Dark Mode
</button>
</footer>
);
};
export default Footer;
const data = useContext(Context);
기존에 수행한 연산의 결과값을 어딘가에 저장해두고 동일한 입력이 들어오면 재활용하는 프로그래밍 기법.
절적히 적용하면 중복 연산을 피할 수 있기 때문에 메모리를 조금 더 쓰더라도 애플리케이션의 성능을 최적화할 수 있다.
React에서 컴포넌트의 랜더링은 한 번 일어나고 끝이 아니라 수시로 계속 일어날 수 있는데, 이전 랜더링과 현재 랜더링 간에 x와 y 값이 동일한 경우, 다시 함수를 호출을 하여 z 값을 구하는 대신, 기존에 메모리의 어딘가에 저장해두었던 z 값을 그대로 사용한다.
const value = useMemo(() => {
return calculate();
},[item])
useEffect처럼 첫 번째 인자로 콜백 함수, 두 번째 인자로 의존성 배열(dependancyArray)을 받는다.
의존성 배열 안에있는 값이 업데이트 될 때에만 콜백 함수를 다시 호출하여 메모리에 저장된 값을 업데이트 해준다.
만약 빈 배열을 넣는다면 useEffect와 마찬가지로 마운트 될 때에만 값을 계산하고 그 이후론 계속 memoization된 값을 꺼내와 사용한다.
import { useState } from "react";
const hardCalculate = (number) => {
console.log("어려운 계산!");
for (let i = 0; i < 99999999; i++) {} // 생각하는 시간
return number + 10000;
};
const easyCalculate = (number) => {
console.log("쉬운 계산!");
return number + 1;
};
function App() {
const [hardNumber, setHardNumber] = useState(1);
const [easyNumber, setEasyNumber] = useState(1);
const hardSum = hardCalculate(hardNumber);
const easySum = easyCalculate(easyNumber);
return (
<div>
<h3>어려운 계산기</h3>
<input
type="number"
value={hardNumber}
onChange={(e) => setHardNumber(parseInt(e.target.value))}
/>
<span> + 10000 = {hardSum}</span>
<h3>쉬운 계산기</h3>
<input
type="number"
value={easyNumber}
onChange={(e) => setEasyNumber(parseInt(e.target.value))}
/>
<span> + 1 = {easySum}</span>
</div>
);
}
export default App;
어려운 계산 & 쉬운 계산기의 값을 변경해도 1초 정도의 딜레이를 거친 후 값이 변경된다.
그 이유는 쉬운 계산기의 input값을 변경하면 함수형 컴포넌트인 App이 리렌더링되면서 내부의 변수들이 초기화되기 때문에 hardCalculate가 다시 실행되기 때문이다.
이럴때 useMemo를 통해 방지할 수 있다.
const hardSum = useMemo(() => {
return hardCalculate(hardNumber);
}, [hardNumber]);
const easySum = easyCalculate(easyNumber);
But 오래 걸리는 로직이 있다고 해도 useEffect hook 함수 등을 이용해서 비동기로 처리하는 방안을 먼저 고려하기 때문에 useMemo가 빛을 발휘할 수 있는 상황은 극히 제한적이며, 브라우저에서 React가 실행되는 속도도 워낙 빠르다보니 왠만한 컴포넌트가 여러 번 랜더링이 일어난다고 해서 실제 심각한 성능 이슈로 이어지는 경우는 의외로 적기 때문에 무분별한 사용한 피하는 것이 좋다.