- src 디렉토리에 useInputs.js 커스텀 훅 컴포넌트 파일을 만든다.
import { useState, useCallback } from "react";
function useInputs(initialForm) {
const [form, setForm] = useState(initialForm);
const onChange = useCallback((e) => {
const { name, value } = e.target;
setForm((form) => ({ ...form, [name]: value }));
}, []);
const reset = useCallback(() => setForm(initialForm), [initialForm]);
return [form, onChange, reset];
}
export default useInputs;
import { useRef, useReducer, useMemo, useCallback } from "react";
import UserList from "./UserList";
import CreateUser from "./CreateUser";
import useInputs from "./useInputs";
function countActiveUsers(users) {
console.log("counting active users...");
return users.filter((user) => user.active).length;
}
const initialState = {
users: [
{ id: 1, username: "bae", age: 22, active: true },
{ id: 2, username: "lee", age: 21, active: false },
{ id: 3, username: "lim", age: 25, active: false },
],
};
function reducer(state, action) {
switch (action.type) {
case "CREATE_USER":
return {
inputs: initialState.inputs,
users: state.users.concat(action.user),
};
case "TOGGLE_USER":
return {
...state,
users: state.users.map((user) =>
user.id === action.id ? { ...user, active: !user.active } : user
),
};
case "REMOVE_USER":
return {
...state,
users: state.users.filter((user) => user.id !== action.id),
};
default:
throw new Error("Unhandled action");
}
}
function App() {
const [state, dispatch] = useReducer(reducer, initialState);
const [form, onChange, reset] = useInputs({
username: "",
age: "",
});
const { username, age } = form;
const nextId = useRef(4);
const { users } = state;
const onCreate = useCallback(() => {
dispatch({
type: "CREATE_USER",
user: {
id: nextId.current,
username,
age,
},
});
nextId.current += 1;
reset();
}, [username, age, reset]);
const onToggle = useCallback((id) => {
dispatch({
type: "TOGGLE_USER",
id,
});
}, []);
const onRemove = useCallback((id) => {
dispatch({
type: "REMOVE_USER",
id,
});
}, []);
const count = useMemo(() => countActiveUsers(users), [users]);
return (
<>
<CreateUser
username={username}
age={age}
onChange={onChange}
onCreate={onCreate}
/>
<UserList users={users} onToggle={onToggle} onRemove={onRemove} />
<div>활성 사용자 수 : {count}</div>
</>
);
}
export default App;
- onCreate 함수의 deps에서 resets는 안넣어도 무방하나 eslint 규칙상 삽입한 것이다.