흐름으로 보면 앞에 했어야 했던(나의 불찰이당~ ㅠㅠ) useReducer 훅에 대해서
오늘 쪼메 알아 보도록 하장. 내 느끼미는 useState를 알면,
useReducer는 그냥 보면 알 수 있을거라 지레 판단하는,성급한 판단의 오류를 범하고 말았당.
그랬당. 다행인 건 성급한 판단의 오류를 오류동에서 했단 거시당.
useState가 너무 단순하여, 조금 더 복잡한 상황에 편하게 쓰라고 만들어 주었당.
문제는 편하게 쓰라고 만들어 주었는데, 처음 본 사람은 그 형태에 당황하게 된다는 거시당.
https://ko.react.dev/reference/react/useReducer
에 가면 설명 뿐만 아니라 예제도 잘 나와있당. react.dev 사이트는 리액트를 하고픈
개발자라면 분명 자주 들러야 할 즐겨찾기 추가가 되어 있어야 할 당근 사이트당.
기본 사용법은 아래와 같당. 당근 첨이라면 낯설당. 사람도 처음 만나면 정보가 없어 당황한당.
?가 붙은 것은 선택적 옵션(있어도 되고, 없어도 되공)을 의미한당.
useReducer는 redux에서 사용하는 형태(지금은 바뀌었당)니 알아 둘 필요가 있당.
const [state, dispatch ] = useReducer( reducer,initialArg,init?);
useReducer는 말로 설명하는 것보다 에제를 보는 것이 매칭이 훨씬 빠르당. 보장
App.jsx
import { useReducer } from "react";
function reducer(state, action) {
console.log("체킁: ", state, action);
switch (action) {
case "inc": {
return { count: state.count + 1 };
}
case "dec": {
return { count: state.count - 1 };
}
case "res": {
return { count: 0 };
}
default:
throw new Error("무얼 보낸거얌 모르겠엉!");
}
}
function App() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
const increment = () => {
dispatch("inc");
};
const decrement = () => {
dispatch("dec");
};
const reset = () => {
dispatch("res");
};
return (
<>
<h1>useReducer 훅 시작이얌</h1>
<h1>카운터: {state.count}</h1>
<button onClick={increment}>증가</button>
<button onClick={decrement}>감소</button>
<button onClick={reset}>리셋</button>
</>
);
}
export default App;
결과는 대략 아래와 같을 지어당.
state는 상태변수를, dispatch는 특정 action을 호출하는 , reducer함수는 dispatch에 받은 action 명령을
처리하는 형태의 흐름을 가지게 된당. useReducer를 만든 사람들이 이렇게 설계하였당.
useReducer를 잘 쓰려면 이 형태를 뇌에 받아들여야 한당.
스마트폰을 사용하는 사람은 일일이 버튼의 위치등을 따지지 않고, 설명대로 사용한당.
대략 느끼미가 찾아왔다면, 쪼메 더 있어 보이게 고쳐보장.
관례적으로 type이란 속성으로 필요한 값(명령의 의미)을 보낸당.
(관례도 다수의 횡포가 될수도, 거꾸로 결정장애자들에겐 다수의 선물이 될 수도...)
App.jsx
import { useReducer } from "react";
const ActionType = {
INC: "inc",
DEC: "dec",
RES: "reset",
};
function reducer(state, action) {
console.log("체킁: ", state, action);
switch (action.type) {
case ActionType.INC: {
return { count: state.count + 1 };
}
case ActionType.DEC: {
return { count: state.count - 1 };
}
case ActionType.RES: {
return { count: 0 };
}
default:
throw new Error("무얼 보낸거얌 모르겠엉!");
}
}
function App() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
const increment = () => {
dispatch({ type: ActionType.INC });
};
const decrement = () => {
dispatch({ type: ActionType.DEC });
};
const reset = () => {
dispatch({ type: ActionType.RES });
};
return (
<>
<div>
<h1>useReducer 훅 시작이얌</h1>
<h1>카운터: {state.count}</h1>
<button onClick={increment}>증가</button>
<button onClick={decrement}>감소</button>
<button onClick={reset}>리셋</button>
</div>
</>
);
}
export default App;
결과는 같고, action을 원시타입에서 객체타입으로
dispatch의 명령을 자바의 enum처럼 고쳤당.(요따구로 한다면, 오타에 대한 체크가 초강력해진당)
눈이 잘 따라간 사람은 이제 그저 몇번만 연습해 본다면, 잘 쓸 수 있을거시당.
눈이 따라가지 못한 사람은 먼저 눈이 따라가야 쓸 수 있음을 잊지 말장.
Hook은 대단한 것이 아니다. 그저 함수일 뿐이고, 편하게 사용할 수 있는 걸
return 해 준당. return 해주는 걸 구조분해로 뽑아서 잘 쓰는 게 첫번째 뽀인또당.
여기서 끝내기엔 쪼메 아쉬움이 없지 않을 수 없지 않지 않을 수 없지 않을 수 없당.
쪼메만 더 진화된 예제를 보고, 눈이 따라가는 연습을 하길 바라지 않을 수 없당.
App.jsx
import { useReducer, useRef } from "react";
const sampleData = [
{ id: 1, name: "성운", age: 40, alias: "안드로메다" },
{ id: 2, name: "규민", age: 35, alias: "귀요미" },
{ id: 3, name: "남혁", age: 30, alias: "나 멱감는다" },
{ id: 4, name: "아린", age: 25, alias: "위대한 대장" },
{ id: 5, name: "재윤", age: 20, alias: "재 윤이맞징?" },
];
const avartar = "https://api.dicebear.com/9.x/micah/svg?seed=";
function reducer(state, action) {
console.log("체킁: ", state, action);
switch (action.type) {
case "add": {
return [action.eagle, ...state];
}
case "remove": {
return state.filter((eagle) => eagle.id != action.eagleId);
}
default:
throw new Error("무얼 보낸거얌 모르겠엉!");
}
}
function App() {
const [eagleFive, dispatch] = useReducer(reducer, sampleData);
const nameRef = useRef(null);
const ageRef = useRef(null);
const aliasRef = useRef(null);
const addEagle = () => {
let maxId = 6;
if (!localStorage.getItem("maxId")) {
localStorage.setItem("maxId", maxId);
} else {
maxId = parseInt(localStorage.getItem("maxId")) + 1;
localStorage.setItem("maxId", maxId);
}
const newEagel = {
id: maxId,
name: nameRef.current.value,
age: ageRef.current.value,
alias: aliasRef.current.value,
};
dispatch({
type: "add",
eagle: newEagel,
});
};
const remEagle = (eagleId) => {
dispatch({
type: "remove",
eagleId,
});
};
return (
<>
<div>
<h1>별거 샘플 예제</h1>
<div style={{ border: "2px solid blueviolet", textAlign: "center" }}>
이름{" "}
<input type="text" ref={nameRef} autoFocus defaultValue={"경미닝"} />
<br />
나이{" "}
<input
type="number"
ref={ageRef}
defaultValue={24}
min={20}
max={90}
style={{ width: "160px" }}
/>
<br />
별명 <input ref={aliasRef} type="text" defaultValue={"에너징"} />
<br />
<button onClick={addEagle}>+</button>
</div>
{eagleFive.map((eagle) => (
<div
key={eagle.id}
style={{ border: "5px groove pink", textAlign: "center" }}
>
<div className="yesol">
<img
src={`${avartar}${eagle.name}`}
alt="아바타"
width={100}
height={100}
/>
</div>
<div className="yesol">
<button onClick={() => remEagle(eagle.id)}>X</button>
<h3>
{eagle.id}: {eagle.name}
</h3>
<h4>{eagle.alias}</h4>
</div>
</div>
))}
</div>
</>
);
}
export default App;
나의 결과는 아래와 같당.
이 결과가 이해되었다고 만족하면 NO! NO! NO! 트리플 NO당.
ajax 비동기로 서버로 부터 데이터를 가져와 초기화하고 서버의 데이터를 변경하는 연습까지 해야한당.
꼬옥 그래야만 한당. 그라고 만족한다면 오케이 하지 아니하지 아니할 수 없음을 아니 모를 수가 없당.
조금 더 깊이 있는 공부를 원하는 사람들을 위해 내가 생각하는 간략하고 간략한
useReducer 함수의 원리를 초 간단하게 표현한 아래 소스를 첨부해 본당. 재밌을지어랑
useReducer 훅 함수의 대략 원리
<!DOCTYPE html>
<meta charset="UTF-8" />
<script>
// 상태 전역변수
let state;
// 초기값 줄 꺼
let initialState = { count: 0 };
// 그냥 코드 좀 예쁘게 할꺼
const types = {
INC: "inc",
DEC: "dec",
RESET: "reset",
};
// 형태가 정해져 있음
const reducer = (state, action) => {
switch (action) {
case types.INC:
return { count: state.count + 1 };
case types.DEC:
return { count: state.count - 1 };
case types.RESET:
return { count: 0 };
default:
throw new Error("이런 타입은 지원 안함");
}
};
// 개인적인 useReducer 형태 추론, 적어도 비슷할 것이 분명
function useReducer(reducer, initState) {
if (!state) state = initState;
return [state, (action) => (state = reducer(state, action))];
}
// App.jsx라 가정
function App() {
const [state, dispatch] = useReducer(reducer, initialState);
console.log("체크1:", state);
console.log("체크2:", dispatch(types.INC));
}
App(); // Rendering 실행 가정
App(); // Re-Rendering 실행 가정
</script>
도움이 되었기를 그저 묵묵히 바라고 바래본당.~~
console.log의 출력이 이해되었다면, 당신은 리액트와 일찍 소통을 열었당.~~
원래 IT 분야는 남성 전용 영역이었당.
과거에 말이당.
이젠 아니당.
그렇다고 경쟁할 필요는 더욱 없당.
오히려 상호 존중과 배려, 이해의 노력이 필요할꺼당.
소프트웨어 공학은 항상 협업을 외치고,
최상의 협업을 위한 방법을 같이 모색하는 거시당.
협업엔 밸런스가 필요하고, 밸런스를 구성하기 위해선
상대방을 있는 그대로 인정하려는 노력은 필수당.
에스파는 훌륭하당.
아마 그럴 girl !!!
https://www.youtube.com/watch?v=dYRITmpFbJ4
React(리액트) 티키타카 37 (Route 이해) (4) | 2025.05.16 |
---|---|
React(리액트) 티키타카 36 (Context API) (2) | 2025.05.13 |
React(리액트) 티키타카 34 (@tanstack/react-query) (0) | 2025.04.08 |
React(리액트) 티키타카 33 (wx-react-gantt) SVAR Gantt (3) | 2025.03.27 |
React(리액트) 티키타카 32 (motion) 애니메이션 (0) | 2025.03.26 |