Context API
사용하기context API
context API 필수 개념
1) createContext
: context 생성 (context 객체)
2) Consumer
: context 변화 감지 (데이터 받아오는 하위 컴포넌트를 지칭)
3) Provider
: context 전달 (상위 컴포넌트에 위치함)
useContext()
: 하위 컴포넌트에서 데이터를 받을 때 사용되는 API
사용 방법
1) FamilyContext 파일 생성 : src > context 폴더에 FamilyContext.js
// FamilyContext.js (context폴더에 있음)
import { createContext } from "react"
export const FamilyContext = createContext(null);
// null : 초기값
// FamilyContext : provider로 하위 컴포넌트에 주입
// -> 하위 컴포넌트 어디든지 내려주기 가능!
2) 전역 상태로 내려줄 상태들이 있는 파일에서, 태그들 가장 바깥쪽에서 provider로 감싸기!
// App.jsx에서 하위 컴포넌트들로 내려주고 싶은 경우
import { FamilyContext } from "...FamilyContext 있는 경로"
function App () {
const name = '길동';
const age = 100;
return (
<FamilyContext.Provider value={{ // ⭐️ value - 내려줄 정보들
name: name,
age: age, // key value 이름 같으면 하나로 생략 가능
}}>
<div>
<input />
</div>
</ FamilyContext.Provider> ⭐️
)
}
value
: 객체를 인자로, 객체 안에는 내려줄 데이터들 들어 있음3) 하위 컴포넌트에서 데이터 받아오는 예시 2가지
// 예시 1)
import { useContext } from "react" ⭐️
import { FamilyContext } from "...FamilyContext 있는 경로" ⭐️
function Father() {
const { name, age } = useContext(FamilyContext); ⭐️
// 구조분해할당 해서 가져오면 context.name 하지 않아도 됨
...생략
}
// 예시 2)
import { useContext } from "react"
import { FamilyContext } from "...FamilyContext 있는 경로"
function Father() {
const context = useContext(FamilyContext); ⭐️
// 이방법으로 가져오면 context.name 이런식으로 붙여야함
console.log(context.name); ⭐️
console.log(context.age);
return {
}
...생략
}
useReducer
context API
+ useReducer
= Redux
1) 설치하기
yarn add redux react-redux
: redux, react-redux 설치하기2) 폴더 구조 설정하기
redux 폴더구조 설정하기 : 이해보다는 그냥 받아들여야 하는 영역임....!
redux
폴더 생성config
폴더 생성configStore.js
파일 생성modules
폴더 생성3) configStore.js 내용 넣기
// 중앙 데이터 관리소(store)를 설정하는 부분
import { createStore } from "redux";
import { combineReducers } from "redux";
const rootReducer = combineReducers({
// 리듀서들 들어오는 자리
});
const store = createStore(rootReducer);
export default store;
4) store 사용하기 위한 내용 index.js
에 넣기
<Provider>
로 감싸주기store={store}
가 필요한 이유import { Provider } from "react-redux";
import store from "./redux/config/configStore";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}> ⭐️
<React.StrictMode>
<App />
</React.StrictMode>
</Provider> ⭐️
);
5) modules 폴더 안에 리듀서들(.js 파일들로 분리) 만들기
// 초기 상태값(state)
const initialState = {
number: 0,
};
// ⭐️ 리듀서 : 'state'의 변화를 일으키는 함수
// (state를 action의 type에 따라 변경하는 함수)
// input(리듀서의 매개변수) : state, action
// ⭐️ action : state의 상태를 어떻게 변경할지를 표현함 (객체임 / type, payload를 가짐)
const counter = (state = initialState, action) => {
switch (action.type) {
// action의 type에 따라서 작업을 수행할 것
case "Plus_One":
// ⭐️ action type을 switch문으로 지정하는군!
// ('Plus_One' type을 Store에 던져주면 아래의 return을 실행함)
return {
number: state.number + 1
}
// console.log(state) // {number: 0} 이라는 객체임!
case "Minus_One":
return {
number: state.number -1
}
default:
return state;
}
};
export default counter;
6) store에 counter 가져와서 저장하기
import counter from "../modules/coutner" ⭐️
const rootReducer = combineReducers({
counter: counter, ⭐️
// 이름 같으면 하나는 생략 가능하기에 conter, 라고 해도 됨
})
const store = createStore(rootReducer);
export default store;
7) 전역 데이터가 필요한 파일 안에서, 중앙 store에 접근하여 counter의 값 읽어오기
=> redux hook 사용! useSelector((state)=>{})
state
(store에 있는 리듀서 전체를 지칭함)import { useSelector } from "react-redux";
function App() {
const counter = useSelector((state)=>{
return state.counter;
})
console.log("counter", counter); // count의 key, value 들어있는 객체 반환(사진 참고)
return <div>현재 카운트 : {counter.number}</div>;
}
export default App;
(이미지 출처: redux 공식 홈페이지)
Store : 중앙 데이터 관리소
UI : 작성하는 컴포넌트
Dispatch : action 객체(type, payload) 를 Store에 던져주기!
Dispatch 가져오기 : redux hook 사용 필요 (useDispatch({})
)
// App.jsx
import { useSelector } from "react-redux";
import { useDispatch } from "react-redux";
function App() {
const dispatch = useDispatch(); ⭐️
const counter = useSelector((state)=>{
return state.counter;
})
return(
<>
<div>현재 카운트 : {counter.number}</div>;
<button
onClick={()=>{
// +1 해주는 로직 : counter 리듀서에서 "Plus_One" 가져오기
dispatch({
type: 'Plus_One'})
// ⭐️ 'Plus_One' type의 action 을 수행해줘!
// 기존값에 + 1 하는 type임)
}}
>+1</button>
<button
onClick={()=>{
dispatch({
type: "Minus_One"
})
}}>
-1</button>
</>
)
}
export default App;
만약 value 이름을 바꾸고 싶으면 conter.js & App.jsx 전부다 바꿔줘야 함
-> 휴먼에러 발생 확률 증가!
reducer 파일 최 상단에 action value 변수로 만들기
export const PLUS_ONE = "Plus_One"
// -> 바꾸고 싶어지면 뒤에만 "counter/Plus_One"하면 다른건 다 안바꿔도 됨
-> value 이름 바꿔주고 싶으면 변수 이름만 바꿔주면 한번에 다 바꿀 수 있음
action creator
// reducer - counter.js
export const plusOne = () => {
return {
type: PLUS_ONE
}
}
// 컴포넌트 - App.jsx
import { plusOne } from "...counter.js 경로"
...생략
dispatch(plusOne()); ⭐️
payload
Ducks 패턴
1) Reducer 함수를 export dafault 하기
2) Action creator 함수들 export 하기
3) Action type은 app/reducer/ACTION_TYPE 형태로 작성
=> 모듈 파일 1개에 Action Type, Action Creator, Reducer가 모두 존재하는 작성 방식!
이 디 액 타 페 써 스
!!
(이) UI에서 event
발생
(디) onClick에서 dispatch
실행(괄호 열고 닫아!)
(액) dispatch의 인자로 action
객체
(타, 페) action객체는 무적권 type
과 payload
(써) reducer
로 ㄱㄱ
(-) action : type과 일치하는 기능을 payload만큼 실행
(스) 결국 Store
안에있는 state
가 변경