728x90
반응형
앞의 게시글과 이어지는 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 |