3. ํ์ ์คํฌ๋ฆฝํธ๋ก ๋ฆฌ์กํธ ์ํ ๊ด๋ฆฌํ๊ธฐ
์นด์ดํฐ ๋ง๋ค์ด๋ณด๊ธฐ
์ธํ ์ํ ๊ด๋ฆฌํ๊ธฐ
useReducer ์ฌ์ฉํด๋ณด๊ธฐ
<src/SampleReducer.tsx>
import React, { useReducer } from 'react';
type Color = 'red' | 'orange' | 'yellow';
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' };
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'SET_COUNT':
return {
...state,
count: action.count // count๊ฐ ์๋์์ฑ๋๋ฉฐ, number ํ์
์ธ๊ฑธ ์ ์ ์์ต๋๋ค.
};
case 'SET_TEXT':
return {
...state,
text: action.text // text๊ฐ ์๋์์ฑ๋๋ฉฐ, string ํ์
์ธ๊ฑธ ์ ์ ์์ต๋๋ค.
};
case 'SET_COLOR':
return {
...state,
color: action.color // color ๊ฐ ์๋์์ฑ๋๋ฉฐ color ๊ฐ Color ํ์
์ธ๊ฑธ ์ ์ ์์ต๋๋ค.
};
case 'TOGGLE_GOOD':
return {
...state,
isGood: !state.isGood
};
default:
throw new Error('Unhandled action');
}
}
function ReducerSample() {
const [state, dispatch] = useReducer(reducer, {
count: 0,
text: 'hello',
color: 'red',
isGood: true
});
const setCount = () => dispatch({ type: 'SET_COUNT', count: 5 }); // count ๋ฅผ ๋ฃ์ง ์์ผ๋ฉด ์๋ฌ๋ฐ์
const setText = () => dispatch({ type: 'SET_TEXT', text: 'bye' }); // text ๋ฅผ ๋ฃ์ง ์์ผ๋ฉด ์๋ฌ ๋ฐ์
const setColor = () => dispatch({ type: 'SET_COLOR', color: 'orange' }); // 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}>SET_COUNT</button>
<button onClick={setText}>SET_TEXT</button>
<button onClick={setColor}>SET_COLOR</button>
<button onClick={toggleGood}>TOGGLE_GOOD</button>
</div>
</div>
);
}
export default ReducerSample;
<App.tsx>
import React from 'react';
import ReducerSample from './ReducerSample';
const App: React.FC = () => {
return <ReducerSample />;
};
export default App;
4. TypeScript์ Context API ํ์ฉํ๊ธฐ
<src/SampleContext.tsx>
import React, { useReducer, useContext, createContext, Dispatch } from 'react';
// ํ์ํ ํ์
๋ค์ ๋ฏธ๋ฆฌ ์ ์ธ
type Color = 'red' | 'orange' | 'yellow';
// ์ํ๋ฅผ ์ํ ํ์
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 ๋ฅผ ๋ฆฌ์กํธ์์ ๋ถ๋ฌ์ฌ ์ ์์), ์ก์
๋ค์ ํ์
์ Dispatch ์ Generics๋ก ์ค์
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 // count๊ฐ ์๋์์ฑ๋๋ฉฐ, number ํ์
์ธ๊ฑธ ์ ์ ์์ต๋๋ค.
};
case 'SET_TEXT':
return {
...state,
text: action.text // text๊ฐ ์๋์์ฑ๋๋ฉฐ, string ํ์
์ธ๊ฑธ ์ ์ ์์ต๋๋ค.
};
case 'SET_COLOR':
return {
...state,
color: action.color // color ๊ฐ ์๋์์ฑ๋๋ฉฐ color ๊ฐ Color ํ์
์ธ๊ฑธ ์ ์ ์์ต๋๋ค.
};
case 'TOGGLE_GOOD':
return {
...state,
isGood: !state.isGood
};
default:
throw new Error('Unhandled action');
}
}
// SampleProvider ์์ useReduer๋ฅผ ์ฌ์ฉํ๊ณ
// SampleStateContext.Provider ์ SampleDispatchContext.Provider ๋ก children ์ ๊ฐ์ธ์ ๋ฐํํฉ๋๋ค.
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 ๋ฅผ ์ฝ๊ฒ ์ฌ์ฉํ๊ธฐ ์ํ ์ปค์คํ
Hooks
export function useSampleState() {
const state = useContext(SampleStateContext);
if (!state) throw new Error('Cannot find SampleProvider'); // ์ ํจํ์ง ์์๋ ์๋ฌ๋ฅผ ๋ฐ์
return state;
}
export function useSampleDispatch() {
const dispatch = useContext(SampleDispatchContext);
if (!dispatch) throw new Error('Cannot find SampleProvider'); // ์ ํจํ์ง ์์๋ ์๋ฌ๋ฅผ ๋ฐ์
return dispatch;
}
<src/App.js>
import React from 'react';
import SampleReducer from './SampleReducer';
import { SampleProvider } from './SampleContext';
const App: React.FC = () => {
return (
<SampleProvider>
<SampleReducer />
</SampleProvider>
);
};
export default App;
<src/SampleReducer.tsx>
import React from 'react';
import { useSampleState, useSampleDispatch } from './SampleContext';
function ReducerSample() {
const state = useSampleState();
const dispatch = useSampleDispatch();
const setCount = () => dispatch({ type: 'SET_COUNT', count: 5 }); // count ๋ฅผ ๋ฃ์ง ์์ผ๋ฉด ์๋ฌ๋ฐ์
const setText = () => dispatch({ type: 'SET_TEXT', text: 'bye' }); // text ๋ฅผ ๋ฃ์ง ์์ผ๋ฉด ์๋ฌ ๋ฐ์
const setColor = () => dispatch({ type: 'SET_COLOR', color: 'orange' }); // 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}>SET_COUNT</button>
<button onClick={setText}>SET_TEXT</button>
<button onClick={setColor}>SET_COLOR</button>
<button onClick={toggleGood}>TOGGLE_GOOD</button>
</div>
</div>
);
}
export default ReducerSample;
'โ๏ธ > React' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
React ๊ณต๋ถํ๊ธฐ(8) - ๋ฆฌ์กํธ ํ๋ก์ ํธ์์ ํ์ ์คํฌ๋ฆฝํธ ์ฌ์ฉํ๊ธฐ (0) | 2021.11.09 |
---|---|
React ๊ณต๋ถํ๊ธฐ(7) - redux-saga of ๋ฆฌ๋์ค ๋ฏธ๋ค์จ์ด (0) | 2021.11.09 |
React ๊ณต๋ถํ๊ธฐ(7) - redux-thunk of ๋ฆฌ๋์ค ๋ฏธ๋ค์จ์ด (0) | 2021.11.09 |
React ๊ณต๋ถํ๊ธฐ(7) - ๋ฆฌ๋์ค ๋ฏธ๋ค์จ์ด (0) | 2021.11.09 |
React ๊ณต๋ถํ๊ธฐ(6) - ๋ฆฌ๋์ค(Redux) (0) | 2021.11.05 |