방명록
- Context API 활용 상태 관리2022년 08월 03일 14시 53분 23초에 업로드 된 글입니다.작성자: 원2728x90반응형
앞의 게시글과 이어지는 context API reducer 를 만들겠음ㅇ
TodoContext.js
import React, {useReducer} from "react"; const initialTodos = [ { id: 1, text: '프로젝트 생성', done: true }, { id: 2, text: '컴포넌트 스타일링하기', done: true }, { id: 3, text: 'Context 만들기', done: false }, { id: 4, text: '기능 구현하기', done: false }, ] function todoReducer(state, action) { switch (action.type) { case 'CREATE': return state.concat(action.todo); case 'TOGGLE': return state.map(todo => todo.id === action.id ? {...todo, done: !todo.done} : todo ); case 'REMOVE': return state.filter(todo => todo.id !== action.id); default: throw new Error(`Unhandled action type: ${action.type}`); } } export function TodoProvider({children}) { const [state, dispatch] = useReducer(todoReducer, initialTodos); return children; }
Context 생성
state, dispatch 를 Context 를 통해 다른 컴포넌트에서 바로 사용 할 수 있게 만들것임
두개의 Context 를 생성하여 불필요한 렌더링을 방지
import React, {createContext, useReducer} from "react"; const initialTodos = [ { id: 1, text: '프로젝트 생성', done: true }, { id: 2, text: '컴포넌트 스타일링하기', done: true }, { id: 3, text: 'Context 만들기', done: false }, { id: 4, text: '기능 구현하기', done: false }, ] function todoReducer(state, action) { switch (action.type) { case 'CREATE': return state.concat(action.todo); case 'TOGGLE': return state.map(todo => todo.id === action.id ? {...todo, done: !todo.done} : todo ); case 'REMOVE': return state.filter(todo => todo.id !== action.id); default: throw new Error(`Unhandled action type: ${action.type}`); } } const TodoStateContext = createContext(); const TodoDispatchContext = createContext(); export function TodoProvider({children}) { const [state, dispatch] = useReducer(todoReducer, initialTodos); return ( <TodoStateContext.Provider value={state}> <TodoDispatchContext.Provider value={dispatch}> {children} </TodoDispatchContext.Provider> </TodoStateContext.Provider> ); }
Context 에서 사용 할 값을 지정 할 때에는 Provider 컴포넌트를 렌더링하고 value를 설정
> 그 내부에 children 렌더링 > 다른 컴포넌트 사용
// 이런식으로 다른 컴포넌트에서 사용가능 import React, { useContext } from 'react'; import { TodoStateContext, TodoDispatchContext } from '../TodoContext'; function Sample() { const state = useContext(TodoStateContext); const dispatch = useContext(TodoDispatchContext); return <div>Sample</div>; }
커스텀 Hook 만들기
컴포넌트에서 useContext 를 직접 사용하지 않고, useContext를 사용하는 커스텀 Hook 을 생성
import React, {createContext, useContext, useReducer} from "react"; const initialTodos = [ { id: 1, text: '프로젝트 생성', done: true }, { id: 2, text: '컴포넌트 스타일링하기', done: true }, { id: 3, text: 'Context 만들기', done: false }, { id: 4, text: '기능 구현하기', done: false }, ] function todoReducer(state, action) { switch (action.type) { case 'CREATE': return state.concat(action.todo); case 'TOGGLE': return state.map(todo => todo.id === action.id ? {...todo, done: !todo.done} : todo ); case 'REMOVE': return state.filter(todo => todo.id !== action.id); default: throw new Error(`Unhandled action type: ${action.type}`); } } const TodoStateContext = createContext(); const TodoDispatchContext = createContext(); export function TodoProvider({children}) { const [state, dispatch] = useReducer(todoReducer, initialTodos); return ( <TodoStateContext.Provider value={state}> <TodoDispatchContext.Provider value={dispatch}> {children} </TodoDispatchContext.Provider> </TodoStateContext.Provider> ); } // 커스텀 Hook export function useTodoState() { return useContext(TodoStateContext); } export function useTodoDispatch() { return useContext(TodoDispatchContext); }
ㄱ 그럼 나중에 이렇게 쓸 수 있다
import React from 'react'; import { useTodoState, useTodoDispatch } from '../TodoContext'; function Sample() { const state = useTodoState(); const dispatch = useTodoDispatch(); return <div>Sample</div>; }
위의 코드에 비해서 간결해졌음, 근데 이건 취향이라서 편한대로 사용하면 될듯
nextId 값 관리
나중에 create를 할때 필요한 Id 값인 nextId 를 만들어주자 고유 ID 가 필요하기 때문ㅇㅇ
import React, {createContext, useContext, useReducer, useRef} from "react"; const initialTodos = [ { id: 1, text: '프로젝트 생성', done: true }, { id: 2, text: '컴포넌트 스타일링하기', done: true }, { id: 3, text: 'Context 만들기', done: false }, { id: 4, text: '기능 구현하기', done: false }, ] function todoReducer(state, action) { switch (action.type) { case 'CREATE': return state.concat(action.todo); case 'TOGGLE': return state.map(todo => todo.id === action.id ? {...todo, done: !todo.done} : todo ); case 'REMOVE': return state.filter(todo => todo.id !== action.id); default: throw new Error(`Unhandled action type: ${action.type}`); } } const TodoStateContext = createContext(); const TodoDispatchContext = createContext(); const TodoNextIdContext = createContext(); export function TodoProvider({children}) { const [state, dispatch] = useReducer(todoReducer, initialTodos); const nextId = useRef(5) return ( <TodoStateContext.Provider value={state}> <TodoDispatchContext.Provider value={dispatch}> <TodoNextIdContext.Provider value={nextId}> {children} </TodoNextIdContext.Provider> </TodoDispatchContext.Provider> </TodoStateContext.Provider> ); } // 커스텀 Hook export function useTodoState() { return useContext(TodoStateContext); } export function useTodoDispatch() { return useContext(TodoDispatchContext); } export function useTodoNextId() { return useContext(TodoNextIdContext); }
커스텀 Hook 에서 에러 처리 (선택)
import React, {createContext, useContext, useReducer, useRef} from "react"; const initialTodos = [ { id: 1, text: '프로젝트 생성', done: true }, { id: 2, text: '컴포넌트 스타일링하기', done: true }, { id: 3, text: 'Context 만들기', done: false }, { id: 4, text: '기능 구현하기', done: false }, ] function todoReducer(state, action) { switch (action.type) { case 'CREATE': return state.concat(action.todo); case 'TOGGLE': return state.map(todo => todo.id === action.id ? {...todo, done: !todo.done} : todo ); case 'REMOVE': return state.filter(todo => todo.id !== action.id); default: throw new Error(`Unhandled action type: ${action.type}`); } } const TodoStateContext = createContext(); const TodoDispatchContext = createContext(); const TodoNextIdContext = createContext(); export function TodoProvider({children}) { const [state, dispatch] = useReducer(todoReducer, initialTodos); const nextId = useRef(5) return ( <TodoStateContext.Provider value={state}> <TodoDispatchContext.Provider value={dispatch}> <TodoNextIdContext.Provider value={nextId}> {children} </TodoNextIdContext.Provider> </TodoDispatchContext.Provider> </TodoStateContext.Provider> ); } // 커스텀 Hook export function useTodoState() { const context = useContext(TodoStateContext); if (!context) { throw new Error(`Cannot find TodoProvider`); } return context; } export function useTodoDispatch() { const context = useContext(TodoDispatchContext); if (!context) { throw new Error(`Cannot find TodoProvider`); } return context; } export function useTodoNextId() { const context = useContext(TodoNextIdContext); if (!context) { throw new Error(`Cannot find TodoProvider`); } return context; }
꼭 이렇게 할 필욘없지만 나중에 오류 찾기 쉬움
근데 난 안할거임ㅇㅇ 귀찮음ㅋ
컴포넌트 TodoProvider 감싸기
Todo 관련 Context 를 사용 할 수 있게 App 에서 TodoProvider 로 감싸기
import './App.css'; import {createGlobalStyle} from "styled-components"; import TodoTemplate from "./components/TodoTemplate"; import TodoHead from "./components/TodoHead"; import TodoList from "./components/TodoList"; import TodoCreate from "./components/TodoCreate"; import {TodoProvider} from "./components/TodoContext"; const GlobalStyle = createGlobalStyle` body { background: #e9ecef; } `; function App() { return ( <TodoProvider> <GlobalStyle/> <TodoTemplate> <TodoHead/> <TodoList /> <TodoCreate /> </TodoTemplate> </TodoProvider> ); } export default App;
TodoHead 에서 사용해보기
import React from "react"; import styled from "styled-components"; import {useTodoState} from "./TodoContext"; const TodoHeadBlock = styled.div` padding-top: 48px; padding-left: 32px; padding-right: 24px; padding-left: 32px; border-bottom: 1px solid #e9ecef; h1 { margin: 0; font-size: 36px; color: #343a40; } .day { margin-top: 4px; color: #868e96; font-size: 21px; } .tasks-left { color: #20c997; font-size: 18px; margin-top: 40px; font-weight: bold; } `; function TodoHead() { const todos = useTodoState(); console.log(todos) return ( <TodoHeadBlock> <h1>2022년 08월 03일</h1> <div className="day">수요일</div> <div className="tasks-left">할일이 3개 남았소</div> </TodoHeadBlock> ); } export default TodoHead;
좋았죠? 728x90반응형'JS Library > React' 카테고리의 다른 글
React Router (0) 2022.08.04 TodoList 기능 구현 (0) 2022.08.03 todolist 만들기 (0) 2022.08.03 styled-components (0) 2022.08.02 react-icons link (0) 2022.08.01 CSS Module (0) 2022.08.01 다음글이 없습니다.이전글이 없습니다.댓글