노력이 좋아서

<step90>'react_ts_SampleContext'

zoaseo 2022. 7. 28. 10:26

1)

SampleContext.tsx

import React, { createContext, Dispatch, useReducer, useContext } from 'react';

type Color = 'red' | 'orange' | 'green'
type State = {
    count: number;
    text: string;
    color: Color;
    isGood: boolean;
}
type Action = {type: 'SET_COUNT'; count: number}
 | {type: 'SET_TEXT'; text: string}
 | {type: 'SET_COLOR'; color: Color}
 | {type: 'TOGGLE_GOOD';}

// 디스패치를 위한 타입 (Dispatch를 리액트에서 불러올 수 있음)
type SampleDispatch = Dispatch<Action>

//  Context 만들기
const SampleStateContext = createContext<State | null>(null);
const SampleDispatchContext = createContext<SampleDispatch | null>(null);

 function reducer(state: State, action: Action) : State {
    switch(action.type){
        case 'SET_COUNT':
            return {
                ...state,
                count: action.count
            }
        case 'SET_TEXT':
            return {
                ...state,
                text: action.text
            }
        case 'SET_COLOR':
            return {
                ...state,
                color: action.color
            }
        case 'TOGGLE_GOOD':
            return {
                ...state,
                isGood: !state.isGood
            }
        default:
            throw new Error('액션이 없어요.');
    }
 }

export function SampleProvider({children}: {children:React.ReactNode}) {
    const [ state, dispatch ] = useReducer(reducer, {
        count: 0,
        text: 'Hello',
        color: 'red',
        isGood: true
    });
    return (
        <SampleStateContext.Provider value={state}>
            <SampleDispatchContext.Provider value={dispatch}>
                {children}
            </SampleDispatchContext.Provider>
        </SampleStateContext.Provider>
    )
}

// state와 dispatch를 쉽게 사용하기 위한 커스텀 hook
export function useSampleState() {
    const state = useContext(SampleStateContext);
    if(!state) throw new Error('찾을 수 없어') // 유효하지 않을 땐 에러를 발생
    return state
}

export function useSampleDispatch() {
    const dispatch = useContext(SampleDispatchContext);
    if(!dispatch) throw new Error('찾을 수 없어') // 유효하지 않을 땐 에러를 발생
    return dispatch
}

ReducerSample2.tsx

import React, { useReducer } from 'react';
import { useSampleDispatch, useSampleState } from './SampleContext';

 const ReducerSample2 = () => {
    const state = useSampleState();
    const dispatch = useSampleDispatch();

    const setCount = () => dispatch({type: 'SET_COUNT', count: 5});
    const setText = () => dispatch({type: 'SET_TEXT', text: 'bye'});
    const setColor = () => dispatch({type: 'SET_COLOR', color: 'orange'});
    const toggleGood = () => dispatch({type: 'TOGGLE_GOOD'});
    return (
        <div>
            <p>
                <code>count : </code> {state.count}
            </p>
            <p>
                <code>text : </code> {state.text}
            </p>
            <p>
                <code>color : </code> {state.color}
            </p>
            <p>
                <code>isGood : </code> {state.isGood ? 'true' : 'false'}
            </p>
            <div>
                <button onClick={setCount}>setcount</button>
                <button onClick={setText}>settext</button>
                <button onClick={setColor}>setcolor</button>
                <button onClick={toggleGood}>togglegood</button>
            </div>
        </div>
    );
};

export default ReducerSample2;