context란?
React 컴포넌트 트리 안에서 전역적(global)이라고 볼 수 있는 데이터를 공유할 수 있도록 고안된 방법이다.
원래 리액트에서는 부모 컴포넌트에서 자식 컴포넌트에게 props로 값을 넘겨주는 방식으로 데이터를 공요할 수 있었다.
useContext
const value = useContext(MyContext);
만들 리액트 부모관계 구조도
천천히 어떤 순서로 이 구조를 만드는지 이해하는게 목표
Store/Context.jsx - export하는 방법에 따른 import하는 형태의 차이
// Context.jsx
// ES6 모듈
export default Store //바로 사용가능
export const a = 10 //객체로 나감
// NodeJS 모듈
module.exports={}
// import받는 파일
import Store, { a } from "./Store/Context";
Store/Context.jsx - 전역상태 기본형 (createContext)
여기서 조금더 나아가면 use를 사용한 Hook을 사용한다. -> 이게 커스텀훅
// Context.jsx
import { createContext } from "react"; //컴포넌트를 만들어주는 역할
export const initialState = { // 화면에 표출할 내용
commentList: [],
loadding: false, // input박스의 submit 값 넣을거임
errors: null,
};
const Store = createContext();
export default Store
Comment.jsx - 전역변수 처리 해주기 (Provider)
가장 먼저 해줘야할것은 컴포넌트끼리 이어주는 전역변수 처리.
createContext로 만든 결과물을 상위에 있는 컴포넌트에 가져와 사용할거니까 Provider를 호출했다.
그 안에 있는 상태와 상태를 변경할 dispatch를 사용하려고 value에 넣었다.
state와 dispatch를 관리하는건 useReducer가 하는 기능과 같으므로 깔끔하게 useReducer를 사용하기로 함
// Comment.jsx
import Store, { initialState } from "./Store/Context";
const Comment = () => {
return(
<Store.Provider value={state,dispatch}>
</Store.Provider>
)
};
Comment.jsx - useReducer 초기값 설정
useReducer를 사용하기 위해 인자값으로 reducer함수와 초기값 initialState를 넣어주었다.
reducer 함수까지 여기다 적으면 너무 코드가 길고 더러워지기때문에 따로 파일을 빼서 작성해주기로 했다.
// Comment.jsx
// 우선순위 = (컴포넌트끼리 이어주는)전역상태 만들기
import Store, { initialState } from "./Store/Context"; // export 하는 형태에 따른 import하는 형태의 차이점
import React, { useReducer, useMemo } from "react";
import reducer, { GET_COMMENT } from "./Store/reducer"; //dispatch({type:GET_COMMNET})
import CommentLayer from "./CommentLayout";
const Comment = () => {
// reducer는 함수라 여기에 작성하면 코드가 너무 길고 더러워짐 -> reducer 파일로 따로 뺌
const [state, dispatch] = useReducer(reducer, initialState);
// const a = {state,dispatch}
// a는 새로운 객체로 생성됨
// Comment가 실행될때마다 함수가 리렌더링됨 = a가 계속 생성되며 메모리에 적재됨
// 그래서 상태가 달라지면 값이 달라지게끔 만들어야함 = useMemo
// 값이기 때문에 useMemo, 함수는 useCallback
// [state] 안에 있는 state가 바뀔때마다 useMemo가 재실행된다.
const defaultValue = useMemo(() => ({state,dispatch}), [state]);
return (
// createContext로 만든 결과물을 가지고 상위에 있는 컴포넌트에 가지고갈때 사용하는 Provider
// <Store.Provider value={}>
// value : state, dispatch = useReducer를 사용해야한다는 말과 같음
// 가져온 state,dispatch 객체 사용하기
<Store.Provider value={{ defaultValue }}>
<CommentLayer />
</Store.Provider>
);
};
export default Comment;
Store/reducer.jsx - reducer 함수 사용하기
reduer함수를 사용하기 위한 state와 action의 관계를 알기 쉽게 swtich 함수로 정리해주었다.
action은 사실 문자열인 type와 payload로 만들어진 객체다.
문자열은 오타내기 쉬우므로 에러를 방지하기 위해 상수 GET_COMMNET로 선언하고,
type과 payload를 사용하기 쉽게 구조분해할당으로 꺼내주었다.
// reducer.jsx
export const GET_COMMNET = 'GET_COMMENT'
const reducer = (state, action) => {
const { type, payload } = action;
switch (type) {
case GET_COMMNET:
return {
...state,
};
default:
return state
}
};
export default reducer;
Comment.jsx - useMemo 사용하기
state과 dispatch를 관리할 reducer 함수의 상수값을 가져왔다.
가져온 state와 dispatch 객체를 value 안에 넣어준다.
아까와 다른 점은 이 객체는 언제나 새롭게 리렌더링될 값이라는 것.
이 기능을 간단하게 해주는 함수가 바로 useMemo다.
// Comment.jsx
import Store, { initialState } from "./Store/Context";
import React, { useReducer } from "react";
import { GET_COMMNET } from "./Store/reducer"; // = dispatch({type:GET_COMMNET})
const Comment = () => {
const [state,dispatch] = useReducer(reducer,initialState)
return(
<Store.Provider value={ {state,dispatch} }>
</Store.Provider>
)
};
useMemo 함수가 실행될때마다 달라질 state와 state값을 달라지게할 함수 dispatch가 있는 콜백이 들어가있다.
두번째 인자에는 배열이 있고, 배열 안에 있는 값이 달라질때마다 useMemo 함수가 재실행된다.
useMemo는 결국 새로운 {state,dispatch} 객체를 반환하며 이는 defaultValue 값이 된다.
// Comment.jsx
import Store, { initialState } from "./Store/Context";
import React, { useReducer,useMemo } from "react";
import { GET_COMMNET } from "./Store/reducer"; // = dispatch({type:GET_COMMNET})
const Comment = () => {
const [state,dispatch] = useReducer(reducer,initialState)
const defaultValue = useMemo(()=>({state,dispatch}),[state])
return(
<Store.Provider value={ defaultValue }>
</Store.Provider>
)
};
이쯤해서 다시 컴포넌트 구조 다시 살펴보기
CommentForm.jsx - submit버튼 이벤트 만들기
- 항상 새 컴포넌트를 사용할때 제일 먼저 생각해야할것은, 전역변수를 가져올 방법이다.
- 이미 Context에서 createStore로 만들어놓은 전역변수가 있으므로 useContext로 가져올 것이다.
- submit버튼을 눌렀을때 상태값이 변하도록 action을 주는 dispatch를 handleSubmit에 넣어놓았다.
- 아직 입력값을 받지 않았으므로 우선 임시데이터를 넣어서 handleSubmit함수를 먼저 완성시키겠다.
- 왜냐하면 데이터는 여기저기로 흐르는데 그 데이터를 만들겠다고 컴포넌트들 들쑤시고다니면 내가 뭘했는지 나중에 헷갈린다. 그러면 이제 답이 없어진다. 그러므로, 지금 붙잡고있는 내용을 먼저 완성시킨 후에 다른 함수나 컴포넌트를 손보자.
- dispatch안에는 action이 들어가고, action은 type과 payload로 만들어진 객체다.
- dispatch를 실행시키면 reducer로 넘어간다. 그러니 reducer를 관리하는 컴포넌트로 넘어가자.
import React,{ useContext } from "react";
import Store from "./Store/Context";
const CommentForm = () => {
const { state, dispatch } = useContext(Store);
const handelSubmit = (e) => {
e.preventDefault();
dispatch()
};
return (
<li>
<form onSubmit={handelSubmit}>
<input type="text" />
<input type="submit" value="댓글쓰기" />
</form>
</li>
);
};
export default CommentForm;
Store/reducer.jsx - 임시데이터 추가하기
임시로 넣어줄 type값을 만들어주었다.
export const CREATE_COMMENT = 'CREATE_COMMENT'
CommentForm.jsx - 임시데이터인 dispatch 만들기
만들어준 type값 CREAT_COMMENT 상수를 가져와 임시데이터 dispatch를 만들어주었다.
이거 지금 적용이 안되는데? 왜지
dispatch({
type:CREATE_COMMENT,
paylaod:{userid:'web7722',context:'asdf',data:'2022-02-01'}
})
'프로그래밍 > react' 카테고리의 다른 글
[220502] redux로 전역상태 관리하는 기초세팅 (0) | 2022.05.09 |
---|---|
[220502] styled-component 사용하기 (0) | 2022.05.08 |
[220428] useReducer (0) | 2022.05.06 |
[220428] React.memo / useMemo / useCallback / Context (0) | 2022.05.05 |
[220427] 코드의 분리 (0) | 2022.05.04 |
댓글