? DOM Handling
? current라는 키를 가지고 있는 객체
const 변수명 = useRef("초기값")
? ref.current = "바꿀 값"
랜더링을 일으키느냐 아니냐의 차이로
useState는 리랜더링을 일으키지만, useRef는 그 자체로는 리랜더링이 되지 않음
useState
setCount(count + 1);
화면 상에 바로 반영됨. (리렌더링이 바로 됨)
useRef
countRef.current++
화면 상에 바로 반영되지 않음. -> 실제로 값이 증가하나, 리렌더링 이후 값이 반영된다.
포커싱 줄 때 연계하여 사용하기
const idRef = useRef("");
//최초 렌더링 시에 이용
useEffect(() => {
idRef.current.focus();
}, [의존성배열*]);
*콜백 함수 내에서 사용되는 외부 변수나 함수들을 넣어야 함 (e.g. state, props, 함수)
의존성 배열에 포함된 값들이 변경될 때마다 실행
의존성 배열이 비어있을 경우는 콜백 함수는 컴포넌트의 첫 번째 렌더링 시에만 생성
return(
<>
<iput type="text" ref={idRef} />
<iput type="password" />
</>
)
? 특정 영역 안에서 데이터를 공유
creactContext ? 생성
useContext ? 구독, 리딩
Provider ? 하위 컴포넌트에 전달
프롭스 드릴링을 하는 대신,
const 어쩌고Context = createContext(null);
<어쩌고Context.Provider **value**={{키 : 밸류}}> <분리된 컴포넌트 /> </어쩌고Context.Provider>
로 감싸서 내려보낸 후,
const {키} = useContext(어쩌고Context);
{키}
출력 값 : 밸류
이때, 내보낼 데이터가 있는 곳과 사용할 곳에는 import를 잊지 말 것
(얘도 리액트 훅이다고 하는데... 말머리가 use가 아니라 이상하다 🧐)
최적화 (OPtimization)
1. memo(React.memo) : 컴포넌트 캐싱
2. useCallback : 함수를 캐싱
3. usemomo : 값을 캐싱
? 최상위 컴포넌트에서 리랜더링 될 경우, 변경된 요소가 없음에도 하위 컴포넌트 모두 리랜더링이 되는 불필요한 랜더링을 막아줌
하위 컴포넌트에 가서
export default React.memo(컴포넌트이름);
? 함수가 참조하는 주소가 같다면 불필요한 랜더링을 막아줄 수 있다는 개념
const 함수명 = useCallback(() => { 콜백 메인 로직 },[의존성배열*]);
*콜백 함수 내에서 사용되는 외부 변수나 함수들을 넣어야 함 (e.g. state, props, 함수)
의존성 배열에 포함된 값들이 변경될 때마다 실행
의존성 배열이 비어있을 경우는 콜백 함수는 컴포넌트의 첫 번째 렌더링 시에만 생성
? 무거운 작업을 수행하는 값을 담아서 리랜더링 시 랜더링을 좀 더 빠르게~~
const 변수명 = useMemo(() => 콜백 함수(), [의존성배열*]);
*콜백 함수 내에서 사용되는 외부 변수나 함수들을 넣어야 함 (e.g. state, props, 함수)
의존성 배열에 포함된 값들이 변경될 때마다 실행
의존성 배열이 비어있을 경우는 콜백 함수는 컴포넌트의 첫 번째 렌더링 시에만 생성
여기서 콜백 함수는 무거운 작업을 수행한다는 가정하에 쓴다.
필요할 때만 useMemo 쓰기
? 전역 상태관리 라이브러리
? 중앙 state 관리소를 사용할 수 있게 도와주는 패키지(라이브러리)
? 리덕스(Redux)에서 액션(Action)과 페이로드(Payload)는 상태 관리를 위한 기본 개념
Local state? useState를 사용하여 생성한 컴포넌트 내부에 있는 state
Global state? 중앙 state 관리소에서 생성된 state

결론 : 그냥 리덕스 쓰자
터미널 오픈
yarn add redux react-redux
src 하위 폴더에 redux 폴더 만들기
[설정 관리] redux 폴더 안에 config 폴더 만들기
2-1. [설정 관리 - 설정 코드] config 폴더 안에 configStore.js 파일 만들기
// 1. rootReducer 만들기
const rootReducer = combineReducers({모듈폴더안에넣을함수*});
*키-밸류 똑같아서 함수명만 적어도 된다.
//2. store 조합
const store = createStore(rootReducer);
//3. store 내보내기
export default store;
⬇️
main.jsx 이동
<Provider store={store}>
<App />
</Provider>
[state 그룹 만들기] redux 폴더 안에 modules 폴더 만들기
3-1. [state 그룹 만들기] modules 폴더 안에 필요한 @@.js 파일 만들기
//action value
const MI_MIC = "MI_MIC"
//action creatpr 만들고 내보내기
export const miMic = (payload) => {
return {
type : MI_MIC,
payload,
}
}
**dispatch(miMic (어쩌구~))로 이용하면 된다.
// 초기값
const initialSate = {
number : 0,
}
//리듀서 함수 만들기
const 모듈폴더안에넣을함수 = (state = initialSate, action*) => {
switch (action.type) {
case "MI_MIC":
return {
[...state, action.payload]}
default;
return state;
}
}
*액션은 객체다. 리듀서 함수는 인자 두 개 받는다.
**return 꼭 필요하다.
//내보내기
export default 모듈폴더안에넣을함수;
리덕스 안에서는 리듀서가 값을 변화시킨다.
모르겠군 😉
? 액션 객체(action object) 내의 데이터 혹은 정보
? 리듀서(reducer)에게 전달되어 상태(state)를 업데이트하는 데 사용
? type 필드 외에, 상태 변경에 필요한 모든 데이터를 포함할 수 있음
? React-Redux 라이브러리에서 제공하는 훅
? Redux 스토어에서 상태를 추출하고 React 컴포넌트에서 사용할 수 있게 해준다.
c
onst 함수명 = useSelector((state) => { return state; });
출력값은 state 안에 모듈폴더안에넣을함수 안에 초기값이 들어있다.
접근할 땐 state.모듈폴더안에넣을함수 로 접근하기
? React-Redux 라이브러리에서 제공하는 훅
? 액션 객체(반드시 type이라는 키를 가져야 함)를 리듀서에 보내는 역할
const 변수명 = useDispatch(); . . onClick={()=>dispatch({ type: "MI_MIC" )}
useState처럼 값을 변경할 수 있다.
타입을 바꾼 이후, modules 폴더 내부에 @@.js 리듀서 파일의 case "type 밸류" return {로직변경}
그래서 모듈 파일 한 개에 action type, action creator, reducer가 모두 존재하는 작성 방식
터미널에서 (리덕스가 깔려있다는 전제)
yarn add @reduxjs/toolkit
//초기 상태값
const initialState = {
키:밸류,
};
// 액션밸류 + 액션 크리에이터 만들기 한 번에
const @@Slice = createSlice({
name : "@@",
initialState,
reducers : {
함수1 : (state, action) => {
return [...state, action.payload]
}
함수2 : () => {
state.키 = state.키값. 어쩌고 메인 로직(payload 활용)
}
}
})
//내보내기
export const {함수1, 함수2} = @@Slice.actions;
//리듀서 함수 만들기
export default @@Slice.reducer;
import {configureStore} form "~";
//만들기와 조합을 한 번에...
const store = configureStore({
reducer : {
@@ : @@Slice
}
})
//store 내보내기
export default store;
액션 -> 디스패처 -> 스토어 -> 뷰 로 관리되는 순환적인 흐름을 강조하는 패턴
Ducks : 코드 구조를 단순화
Flux : 데이터 흐름을 체계화
액션...? 슬라이스...? 페이로드...? 🙃? 리듀서...? 😌
yarn add react-router-dom
e.g.
1. src 폴더 내에 pages 폴더 생성
1-1. pages 폴더 내에 Home.jsx / About.jsx / Contact.jsx / Works.jsx 파일 만들기
2. src 폴더 내에 shared 폴더 만들기
2-1. shard 폴더 내에 Router.jsx 만들기
Router.jsx 파일
임포트 해야 함
return (
<BrowserRouter>
<Routes>
/*route 넣기*/
<Route path='/' element={<Home />} />
<Route path='/about' element={<About />} />
<Route path='/contact' element={<Contact />} />
<Route path='/works' element={<Works />} />
</Routes>
</BrowserRouter>
)
2-2. ⬇️ 리팩토링
return (
<BrowserRouter>
<Layout>
<Routes>
/*route 넣기*/
<Route path='/' element={<Home />} />
<Route path='/about' element={<About />} />
<Route path='/contact' element={<Contact />} />
<Route path='/works' element={<Works />} />
</Routes>
</Layout>
</BrowserRouter>
)
한 개 더
Layout.jsx 파일
function Layout({children) {
return (
<div>
<Header />
<div style={{}}>{children}</div>
</div>
);
}
App.jsx에 router 가져오기
return (
<Router />
)
const navigate = useNavigate(); {navigate("/works")}
<Link to = "/contact">contact로 이동하기</Link>
object 형태(키-밸류)로 존재
hash, key, pathname: "/works", search, state
const location = useLocation(); {location.pathname.slice(1)}
e.g. 출력값 : work
? 웹 애플리케이션에서 URL 경로의 일부를 동적으로 생성하고 사용
<Route pathe="work/:id" element={<works />} />
const params = useParams();
출력 값 : id : 밸류값
const targetWork = data.find((work) => return work.id === Number(params.id); })
하단에 {targetWork.키값} 으로 사용
? 전체적으로 레이아웃으로 적용하지 않고 부분적으로 적용하고 싶을 때... 전 그냥 레이아웃 쓰고 싶어요...
<Route path=dashboard element={<DashBoardLaout />}> <Route path= "myPage" element={<myPage />}> <Route path= "test" element={<test />}> </Route>
이렇게 여닫고 내부에다 두 파일 넣기.
return (<><h1>대쉬보드!</h1><outlet /></>)
=> 대쉬보드는 남아있고, 페이지와 테스트가 보인다.
? Backend as a Service
? 웹 및 모바일 애플리케이션 개발을 위해 백엔드 서비스를 제공하는 클라우드 서비스 모델
? BaaS는 개발자가 서버 관리, 데이터베이스 설정, 사용자 인증, 푸시 알림, 파일 저장 및 기타 백엔드 기능을 쉽게 사용 가능
관계형 데이터베이스(SQL) 사용
터미널 열고
yarn add @supabase/supabase-js
Supabase
Table Editor -> Create a new table under @@(선택 사항)
(*보안 선택, columns에 필요한 정보 선택) -> save
리액트에서 해당 코드 접근하기
supabaseClient.js 파일 만들기 (App.jsx와 동일 선상)
import { createClient } from "@supabase/supabase-js";
// 1) project url
const SUPABASE_PROJECT_URL = "YOUR_SUPABASE_URL";
// 2) anon key
const SUPABASE_ANON_KEY = "YOUT_SUPABASE_KEY";
const supabase = createClient(SUPABASE_PROJECT_URL, SUPABASE_ANON_KEY);
export default supabase;
Supabase의 하단에 project URL, API key를 넣기
Supabase 에서 초록색 insert 버튼 누르면 데이터 넣을 수 있다.
데이터를 가져오기 위해서는 useEffect (최초 랜더링 시) 사용하기
const FetchData = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
const fetchData = async () => {
const { data, error } = await supabase.from("만만든거이름").select("*");
if (error) {
console.log("error => ", error);
} else {
console.log("data => ", data);
setUsers(data);
}
};
fetchData();
}, []);`
그 외 추가, 수정, 삭제도 있는데 supabase 공식 문서 살펴 보기로~
오늘은 배운 게 많다...!