240521 TIL_개인 프로젝트3 (개인 지출 관리 사이트 제작), React 강의 (React hooks | context API | memoization | Redux | React Router DOM | Dynamic Route | Supabase)

미밍·2024년 5월 21일
2

우당탕탕 개발 일기

목록 보기
40/108

리액트

리렌더링의 발생 조건

  1. 컴포넌트에서의 state의 변경
  2. 컴포넌트가 내려받은 props의 변경
  3. 부모 컴포넌트가 리렌더링 됐을 경우 자식 컴포넌트는 모두

리액트 훅 (React hooks)

useRef

? DOM Handling
? current라는 키를 가지고 있는 객체

const 변수명 = useRef("초기값")

useRef 접근법

? ref.current = "바꿀 값"

useState, useRef

랜더링을 일으키느냐 아니냐의 차이로
useState는 리랜더링을 일으키지만, useRef는 그 자체로는 리랜더링이 되지 않음

useState

setCount(count + 1);

화면 상에 바로 반영됨. (리렌더링이 바로 됨)

useRef

countRef.current++

화면 상에 바로 반영되지 않음. -> 실제로 값이 증가하나, 리렌더링 이후 값이 반영된다.

useEffect, useRef

포커싱 줄 때 연계하여 사용하기

const idRef = useRef("");

//최초 렌더링 시에 이용
useEffect(() => {
	idRef.current.focus();
}, [의존성배열*]);
*콜백 함수 내에서 사용되는 외부 변수나 함수들을 넣어야 함 (e.g. state, props, 함수)
의존성 배열에 포함된 값들이 변경될 때마다 실행
의존성 배열이 비어있을 경우는 콜백 함수는 컴포넌트의 첫 번째 렌더링 시에만 생성

return(
	<>
    	<iput type="text" ref={idRef} />
        <iput type="password" />
    </>
)

useContext

context API

? 특정 영역 안에서 데이터를 공유

필수 개념

creactContext ? 생성
useContext ? 구독, 리딩
Provider ? 하위 컴포넌트에 전달

useContext 사용 방법

프롭스 드릴링을 하는 대신,

  1. 어쩌고Context.js 파일을 만들고

const 어쩌고Context = createContext(null);

  1. 내보낼 데이터가 있는 곳에

<어쩌고Context.Provider **value**={{키 : 밸류}}> <분리된 컴포넌트 /> </어쩌고Context.Provider>

로 감싸서 내려보낸 후,

  1. 사용할 곳(안 이어져도 됨. 예를 들어 사용처의 손자여도 가능)에 넣고,

const {키} = useContext(어쩌고Context);

  1. 이후 return 아래에 사용하면 된다.

{키}
출력 값 : 밸류

이때, 내보낼 데이터가 있는 곳과 사용할 곳에는 import를 잊지 말 것

memoization

(얘도 리액트 훅이다고 하는데... 말머리가 use가 아니라 이상하다 🧐)

최적화 (OPtimization)
1. memo(React.memo) : 컴포넌트 캐싱
2. useCallback : 함수를 캐싱
3. usemomo : 값을 캐싱

memo (React.memo)

? 최상위 컴포넌트에서 리랜더링 될 경우, 변경된 요소가 없음에도 하위 컴포넌트 모두 리랜더링이 되는 불필요한 랜더링을 막아줌

memo (React.memo) 사용 방법

하위 컴포넌트에 가서

export default React.memo(컴포넌트이름);

useCallback

? 함수가 참조하는 주소가 같다면 불필요한 랜더링을 막아줄 수 있다는 개념

useCallback 사용 방법

const 함수명 = useCallback(() => { 콜백 메인 로직 },[의존성배열*]);
*콜백 함수 내에서 사용되는 외부 변수나 함수들을 넣어야 함 (e.g. state, props, 함수)
의존성 배열에 포함된 값들이 변경될 때마다 실행
의존성 배열이 비어있을 경우는 콜백 함수는 컴포넌트의 첫 번째 렌더링 시에만 생성

useMemo

? 무거운 작업을 수행하는 값을 담아서 리랜더링 시 랜더링을 좀 더 빠르게~~

useMemo 사용 방법

const 변수명 = useMemo(() => 콜백 함수(), [의존성배열*]);
*콜백 함수 내에서 사용되는 외부 변수나 함수들을 넣어야 함 (e.g. state, props, 함수)
의존성 배열에 포함된 값들이 변경될 때마다 실행
의존성 배열이 비어있을 경우는 콜백 함수는 컴포넌트의 첫 번째 렌더링 시에만 생성

여기서 콜백 함수는 무거운 작업을 수행한다는 가정하에 쓴다.
필요할 때만 useMemo 쓰기

custom hooks

custom hook의 주의사항

  1. 함수명은 use로 시작하기
  2. hooks 폴더 내의 파일 이름은 원하는 대로 쓰기. (@@@.js)

custom hook 사용 방법

  1. 만들고 싶은 함수 만들기
  2. 파일 내부에 return에 [state명, 함수명]
  3. 쓰고 싶은 곳으로 가서 const ~~~ = 함수명

Redux

? 전역 상태관리 라이브러리
? 중앙 state 관리소를 사용할 수 있게 도와주는 패키지(라이브러리)
? 리덕스(Redux)에서 액션(Action)과 페이로드(Payload)는 상태 관리를 위한 기본 개념

Local state, Global state

Local state? useState를 사용하여 생성한 컴포넌트 내부에 있는 state
Global state? 중앙 state 관리소에서 생성된 state
globalState

Context API vs Redux

  1. 성능 최적화
  2. 상태 로직의 중앙화와 일관성
  3. 강력한 미들웨어와 개발 도구

결론 : 그냥 리덕스 쓰자

redux 사용 방법

터미널 오픈

yarn add redux react-redux

  1. src 하위 폴더에 redux 폴더 만들기

  2. [설정 관리] 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>
    	
  3. [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 모듈폴더안에넣을함수;

리덕스 안에서는 리듀서가 값을 변화시킨다.
모르겠군 😉

payload

? 액션 객체(action object) 내의 데이터 혹은 정보
? 리듀서(reducer)에게 전달되어 상태(state)를 업데이트하는 데 사용
? type 필드 외에, 상태 변경에 필요한 모든 데이터를 포함할 수 있음

useSelector

? React-Redux 라이브러리에서 제공하는 훅
? Redux 스토어에서 상태를 추출하고 React 컴포넌트에서 사용할 수 있게 해준다.

useSelector 사용 방법

const 함수명 = useSelector((state) => { return state; });
출력값은 state 안에 모듈폴더안에넣을함수 안에 초기값이 들어있다.
접근할 땐 state.모듈폴더안에넣을함수 로 접근하기

useDispatch

? React-Redux 라이브러리에서 제공하는 훅
? 액션 객체(반드시 type이라는 키를 가져야 함)를 리듀서에 보내는 역할

useDispatch 사용 방법

const 변수명 = useDispatch(); . . onClick={()=>dispatch({ type: "MI_MIC" )}

useState처럼 값을 변경할 수 있다.
타입을 바꾼 이후, modules 폴더 내부에 @@.js 리듀서 파일의 case "type 밸류" return {로직변경}

Ducks 패턴 🐤

Duck 패턴으로 작성하기

  1. reducer 함수를 export default
  2. action creator 함수를 export
  3. action type은 app/reducer/ACTION_TYPE 형태로 작성한다.
    (외부 라이브러리가 필요할 경우 UPPER_SNAKE_CASE로 작성)

그래서 모듈 파일 한 개에 action type, action creator, reducer가 모두 존재하는 작성 방식

RTK(Redux ToolKit)

터미널에서 (리덕스가 깔려있다는 전제)

yarn add @reduxjs/toolkit

RTK 사용 방법

  1. redux 폴더 안에 slices 폴더 만들기 (모듈 폴더와 비슷한 기능)
  2. slices 폴더 안에 @@Slice.js 파일 만들기
//초기 상태값
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;
  1. configStore.js 파일로 가서
import {configureStore} form "~";

//만들기와 조합을 한 번에...
const store = configureStore({
	reducer : {
    	@@ : @@Slice
    }
})

//store 내보내기
export default store;

Flux 패턴

액션 -> 디스패처 -> 스토어 -> 뷰 로 관리되는 순환적인 흐름을 강조하는 패턴

Ducks vs Flux

Ducks : 코드 구조를 단순화
Flux : 데이터 흐름을 체계화

액션...? 슬라이스...? 페이로드...? 🙃? 리듀서...? 😌

React Router DOM

React Router DOM 설치 방법

yarn add react-router-dom

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>
	);
}
  1. App.jsx에 router 가져오기

    return (
    	<Router />
    )

React Router DOM Hooks

useNavigate 사용 방법

const navigate = useNavigate(); {navigate("/works")}

<Link to = "/contact">contact로 이동하기</Link>

useLocataion

object 형태(키-밸류)로 존재
hash, key, pathname: "/works", search, state

useLocataion 사용 방법

const location = useLocation(); {location.pathname.slice(1)}
e.g. 출력값 : work

Dynamic Route

? 웹 애플리케이션에서 URL 경로의 일부를 동적으로 생성하고 사용

<Route pathe="work/:id" element={<works />} />

useParams 사용 방법

const params = useParams();
출력 값 : id : 밸류값

const targetWork = data.find((work) => return work.id === Number(params.id); })
하단에 {targetWork.키값} 으로 사용

중첩된 라우트 사용 방법

? 전체적으로 레이아웃으로 적용하지 않고 부분적으로 적용하고 싶을 때... 전 그냥 레이아웃 쓰고 싶어요...

  1. <Route path=dashboard element={<DashBoardLaout />}> <Route path= "myPage" element={<myPage />}> <Route path= "test" element={<test />}> </Route>

이렇게 여닫고 내부에다 두 파일 넣기.

  1. 대쉬보드.jsx에서 outlet 추가

    return (<><h1>대쉬보드!</h1><outlet /></>)

=> 대쉬보드는 남아있고, 페이지와 테스트가 보인다.

BaaS

? Backend as a Service
? 웹 및 모바일 애플리케이션 개발을 위해 백엔드 서비스를 제공하는 클라우드 서비스 모델
? BaaS는 개발자가 서버 관리, 데이터베이스 설정, 사용자 인증, 푸시 알림, 파일 저장 및 기타 백엔드 기능을 쉽게 사용 가능

Supabase

관계형 데이터베이스(SQL) 사용

Supabase 설치 방법

터미널 열고

yarn add @supabase/supabase-js

Supabase 사용 방법

  1. Supabase
    Table Editor -> Create a new table under @@(선택 사항)
    (*보안 선택, columns에 필요한 정보 선택) -> save

  2. 리액트에서 해당 코드 접근하기
    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를 넣기

  1. Supabase 에서 초록색 insert 버튼 누르면 데이터 넣을 수 있다.

  2. 데이터를 가져오기 위해서는 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 공식 문서 살펴 보기로~
오늘은 배운 게 많다...!

profile
프론트앤드; Frontend

0개의 댓글