기본적인 메인 페이지의 틀은 완성했으니 기능을 추가할 차례다.
메인 페이지는 여전히 두 개의 컴포넌트로 구성되었으나, 모듈화를 진행하였다.
import { React, useEffect, useReducer } from 'react';
import { TeamBar, MainScreen } from '../../components';
import './Main.scss';
const initalState = {
stateData: {
curTeam: 0,
curTest: 0,
},
teamData: [
{ index: 0, name: 'asg Team', test: ['qwre', 'asdg', 'asd'] }, // 각 테스트는 객체 형태여야 함.
{ index: 1, name: 'qwer Team', test: ['test1', 'test2', 'test3'] },
],
};
const reducer = (state, action) => {
const stateData = state.stateData;
const teamData = state.teamData;
switch (action.type) {
case 'addTeam': {
const newTeamIndex = teamData.length;
const newTeamName = action.name;
const newTeam = { index: newTeamIndex, name: newTeamName, test: [] };
stateData.curTeam = newTeamIndex;
state.teamData.push(newTeam);
return { ...state };
}
case 'addTest': {
console.log('실행됨!');
const curTeamIndex = action.curTeam; // state에서 끌어다 써도 될 듯
const testName = action.newTestName;
let newArray = teamData[curTeamIndex].test;
const temp = [...newArray, testName];
// newArray.push(testName);
teamData[curTeamIndex].test = temp;
console.log(...newArray);
return { ...state };
}
case 'changeTeam': {
stateData.curTeam = action.dst;
stateData.curTest = 0;
return { ...state };
}
case 'changeTest': {
stateData.curTest = action.dst;
return { ...state };
}
default: {
return state;
}
}
};
const Main = () => {
const [state, dispatch] = useReducer(reducer, initalState);
const curTeam = initalState.stateData.curTeam;
const curTest = initalState.stateData.curTest;
const teamData = state.teamData;
useEffect(() => {
console.log(state);
}, [state]);
// 여기서 라우팅을 해?
return (
<>
{teamData && (
<div className="page-main">
<TeamBar teamData={teamData} dispatch={dispatch} />
<MainScreen
teamData={teamData}
curTeam={curTeam}
curTest={curTest}
dispatch={dispatch}
/>
</div>
)}
</>
);
};
export default Main;
useReducer에 대해서는 링크 참조.
useReducer를 이용해서 state를 전역적으로 관리하게끔 하였다.
dispatch
를 props로 보내면 자식 프로세스에서는 dispatch
를 action 객체 형태로 정제해서 보낸다. 어디에서는 dispatch
를 가지고 있다면 reducer
함수에서 받아서 case에 맞는 작동을 취한다.
import { React, useState } from 'react';
import TeamBarHeader from './TeamBarHeader';
import TeamBarBody from './TeamBarBody';
import Modal from '../../util/Modal';
import useModalHandle from '../../util/hooks/useModalHandle';
import './TeamBar.scss';
const TeamBar = ({ teamData, dispatch }) => {
const [open, close, isOpen] = useModalHandle();
const [teamName, setTeamName] = useState('');
const changeName = e => {
setTeamName(e.currentTarget.value);
};
const addTeamEvent = e => {
e.preventDefault();
if (teamName === '') return;
dispatch({ type: 'addTeam', name: teamName });
setTeamName('');
close();
};
const content = (
<div className="team-modal">
<form action="input" onSubmit={addTeamEvent}>
<div>Create New Team</div>
<div>Name Your Team Before choosing a new project.</div>
<input
onChange={changeName}
maxLength="12"
type="text"
value={teamName}
/>
</form>
</div>
);
return (
<div className="team-bar">
<TeamBarHeader />
<TeamBarBody teamData={teamData} dispatch={dispatch} open={open} />
<Modal isOpen={isOpen} close={close} content={content} />
</div>
);
};
export default TeamBar;
import { useState } from 'react';
const useModalHandle = () => {
const [isOpen, setIsOpen] = useState(false);
const open = () => {
setIsOpen(true);
};
const close = () => {
setIsOpen(false);
};
return [open, close, isOpen];
};
export default useModalHandle;
커스텀 훅으로 만들어 놓은 useModalHandle
을 써서 모달을 관리할 수 있는 isOpen
, 참과 거짓으로 값을 바꾸는 콜백함수 open
,close
를 받는다.
content
라는 객체에 컴포넌트를 통째로 넣어주고 Modal
컴포넌트의 props로 보낸다. isOpen
이 참일 경우 content
를 렌더링 할 것이다.
import React from 'react';
const Modal = ({ isOpen, close, content }) => {
const isOuter = e => {
const clicked = e.target.className;
if (clicked === 'modal') close();
};
return (
<>
<>
{isOpen && (
<>
<div className="modal" onClick={isOuter}>
{' '}
{content}
</div>
</>
)}
</>
</>
);
};
export default Modal;
재사용하기 용이한 모달창 틀을 만들었다.
전체를 감싸는 div 태그를 하나 만들고 이벤트를 걸어서 해당 태그를 클릭한 경우 모달창을 끄게끔 close
로 isOpen
을 거짓으로 바꾼다.
const reducer = (state, action) => {
const stateData = state.stateData;
const teamData = state.teamData;
switch (action.type) {
case 'addTest': {
console.log('실행됨!');
const curTeamIndex = action.curTeam; // state에서 끌어다 써도 될 듯
const testName = action.newTestName;
let newArray = teamData[curTeamIndex].test;
const temp = [...newArray, testName];
console.log(temp);
teamData[curTeamIndex].test = temp;
console.log(teamData[curTeamIndex].test);
return { ...state };
}
default: {
return state;
}
}
};
addTest
액션이 한 번 실행되는 동안 state가 두 개씩 늘어나는 이슈 발생. 코드를 아래와 같이 바꾸었더니 해결. 원인은 아직 분석하지 못했으나 원래 state를 참조하는 과정에서 생긴 이슈같다.
const reducer = (state, action) => {
const stateData = state.stateData;
const teamData = state.teamData;
switch (action.type) {
case 'addTest': {
console.log('실행됨!');
const curTeamIndex = action.curTeam; // state에서 끌어다 써도 될 듯
const testName = action.newTestName;
const temp = [...action.curTestArray, testName];
// newArray.push(testName);
teamData[curTeamIndex].test = temp;
return { ...state };
}
default: {
return state;
}
}
};