-
Notifications
You must be signed in to change notification settings - Fork 0
아키텍처
Yeonu Kim edited this page Aug 25, 2024
·
3 revisions
웹사이트의 폴더 구조는 다음과 같습니다.
│─public: 정적 파일 저장 (css, image 등)
│ └─css
└─src
├─components: 각 페이지에 들어갈 컴포넌트의 view 저장
│ ├─admin
│ ├─common
│ └─user
├─pages: 각각의 페이지 저장
├─states: state 정의 저장
├─utils
└─viewModel: custom hook 저장
MVVM 아키텍처를 사용하여 폴더를 정리하였습니다.
-
MVVM이 무엇인가요?
각각의 state를 정의합니다. state 폴더에서 model을 담당하고 있습니다. 현재는 zustand를 사용하여 state를 관리하고 있습니다.
// Model 예시 코드(attendStore)
import create from 'zustand';
const useAttendStore = create((set) => ({
// attend state에 대해 정의합니다.
attend: {
userId: null,
sessionId: null,
attendIdx: 0,
status: false,
},
attends: [],
// 각각의 state를 관리하는 주요 함수들을 정의합니다.
setAttend: (newAttend) => set((state) => ({
attend: {
...state.attend,
...newAttend,
}
})),
setUpdateAttends: (newAttend) => set((state) => {
const filteredAttends = state.attends.filter(
(attend) =>
attend.userId !== newAttend.userId ||
attend.sessionId !== newAttend.sessionId ||
attend.attendIdx !== newAttend.attendIdx
);
return { attends: [...filteredAttends, newAttend] };
}),
}));
export default useAttendStore;
보이는 화면을 정의합니다. component 폴더에서 view를 담당하고 있습니다.
// View 예시 코드 (AttendUpdateList)
const AttendUpdateList = () => {
const location = useLocation();
const { userId } = location.state || {};
// viewModel 부분 불러오기
const { attendanceRecords, loading, error, toggleAttend } = useAttendUpdateList(userId);
// 보이는 것과 관련된 함수 선언
// e.g. 출석 횟수가 3회일때는 초록색으로 보이도록 처리
const calculateStatus = (attendList) => {
if (!attendList || attendList.length === 0) return COLORS.light_gray;
const checkedCount = attendList.filter((item) => item.status).length;
if (checkedCount === 3) return COLORS.green;
if (checkedCount >= 1) return COLORS.orange;
return COLORS.red;
};
// 보이는 부분 Return
if (loading) return <Container>Loading...</Container>;
if (error) return <Container>Error: {error}</Container>;
return (
<AttendanceContainer>
{attendanceRecords.map((record, record_index) => {
if (!record.session_date) {
return null;
}
const { month, date, day } = getLocal(record.session_date);
const finalStatus = calculateStatus(record.attendList);
const attendListLength = record.attendList ? record.attendList.length : 0;
const grayCirclesNeeded = 3 - attendListLength;
return (
<SessionContainer key={record_index}>
<SessionName>{record.session_name}</SessionName>
<RowContainer>
<OnAirCircle color={finalStatus} />
<DateContainer>
{month}/{date}
<br />
{day}
</DateContainer>
{record.attendList && record.attendList.length > 0
? record.attendList.map((attend, attend_index) => (
<OnAirCircle
key={attend_index}
color={attend.status ? COLORS.green : COLORS.red}
onPress={() => toggleAttend(record_index, attend_index)}
/>
))
: null}
{[...Array(grayCirclesNeeded)].map((_, i) => (
<OnAirCircle
key={attendListLength + i}
color={COLORS.light_gray}
/>
))}
</RowContainer>
</SessionContainer>
);
})}
</AttendanceContainer>
);
};
export default AttendUpdateList;
보이는 화면과 모델 사이의 로직을 관리합니다. Custom Hook형식으로 관리하고 있습니다.
// viewModel 예시 코드 (adminHook)
const useAttendUpdateList = (userId) => {
// 필요한 state 불러오기
const { attendanceRecords, loading, error } = useAttendUpdate(userId);
const { setUpdateAttends } = useAttendStore();
const { updateData } = useListDataStore();
// 로직 처리에 필요한 함수 선언
// e.g. 현재 출석 현황을 toggle 형식으로 변경하여 저장하는 함수
const toggleAttend = (record_index, attend_index) => {
const target_record = attendanceRecords[record_index];
const target_attend = target_record.attendList[attend_index];
const new_attend = {
userId: userId,
sessionId: target_record.session,
attendIdx: target_attend.attendIdx,
status: !target_attend.status,
};
setUpdateAttends(new_attend);
updateData((prev) => {
const newRecords = [...prev];
newRecords[record_index].attendList[attend_index].status =
!newRecords[record_index].attendList[attend_index].status;
return newRecords;
});
};
return { attendanceRecords, loading, error, toggleAttend };
};