본문 바로가기

공부일지/Project

비전공자의 프로젝트 만들기) 스케줄 프로젝트 만들기 - part2 오류 수정 후 오류 수정....

728x90
반응형
반응형

스케줄 프로젝트 만들기 - part2

 

 

저번일지에서 리덕스 설치 후 오류 수정하러 간다고 했던 MIN입니다.

오류를 수정하고 다시 돌아왔습니다.

 

하지만 아시죠... 오류를 수정하면 또 다른 오류가 나온다는 거를............ 나름 인강을 듣고 리덕스 쪽에 이해를 했다고 생각했던 제가 너무 안일했던 거 같네요... 상태관리... 아직은 저 같은 주니어한테는 어렵네요.

 

그럼 저번시간에 생겼던 오류가 무엇이냐면...

바로 리액트 18버전에서는 랜더링 하는 방식이 다른데 제가 무지성으로 블로그에 있는 글을 막 들고 와서 작성을 하는 바람에 생겼던 오류였더라고요..... 당연히 그 문제는 아닐 거라 생각해서 진짜 한시간 넘게 오류 찾았어요....

 

이번시간에도 리덕스 때문에 데이터가 안 받아지고 데이터 저장이 안 되고 하는 그런 우여곡절 끝에 세션 스토리지에 까지 저장하는 기능까지 작업하게 되었습니다.

 

그러면서 리덕스 action 페이지의 코드도 변경되었는데 한번 확인해 볼까요?? 

 

뭔가 혼자 이렇게 해놨다는 게 기뻐서 글 쓰면서 들떠 있는 게 느껴지네요 ㅎㅎ

 

아직까지도 일정등록 기능 밖에 없지만

 

/reducers/schedule.js

let keyId = 0

export const initalSchedule = ({title, date, content}) => {
    return {
        scheduleList:{
            keyId:keyId++,
            title,
            date,
            content
        }
    }
}
const currentSchedule = {
    scheduleList:[],
}


export const ADD = "ADD_SCHEDULE";
export const DELETE = "SCHEDULE/DELETE";
export const EDIT = "SCHEDULE/EDIT";
export const SUCCESS = "SCHEDULE/SUCCESS";


export const add_schedule = ({title, date, content}) => {
    return{
        type:ADD, 
        scheduleList:{
            keyId:keyId++,
            title,
            date,
            content
        }
    }
};

const schedule = (state = currentSchedule, action) => {
    switch(action.type){
        case ADD :
            return {
                scheduleList : [...state.scheduleList, action.scheduleList]
            }
        default :
        return state
    }
}

export default schedule;

 

action 페이지의 코드가 몇 개 추가되고 몇 개는 없어졌습니다.

솔직히 이 action페이지 때문에 시간이 오래 걸렸었어요ㅠㅠ. 왜냐면 이것저것 해본다고 객체 타입으로도 저장해 보고 배열로도 저장해보고 function으로도 해보고 const, let 도 써보고 써봤지만 저한테는 지금 저 코드가 딱 알맞은 거 같더라고요.

 

add_schedule의 기능은 tppe:ADD 위에서 선언했던 타입을 들고 와 scheduleList라는 객체를 만들어서 저장하는 방식으로 했습니다.

 

아 글 쓰다 보니 initalSchedule 이 부분을 지우지 않았네요. 처음에는 저기에 받아온 데이터를 넣고 출력하는 방식으로 했는데 제가 원하는 데이터로 저장이 안 되고 조금 이상하더라고요.

 

그래서 아래의 add_schedule 코드로 변경해서 return도 스케줄 리스트에 기존 state의 리스트와 신규 리스트를 저장하는 방식으로 했습니다.

 

선배님들 조금 더 좋은 방식이 있으면 댓글로 알려주시면 감사드리겠습니다.

 

아 그러고 보니 index.js 파일은 제가 안 보여 드렸네요.

import React from 'react';
import ReactDOM from 'react-dom/client';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import App from './App';
import { persistStore } from "redux-persist";
import { PersistGate } from "redux-persist/integration/react";
import persistReducer from "./reducers";



import 'semantic-ui-css/semantic.min.css'
import './index.css';

const store = createStore(persistReducer);
const root = ReactDOM.createRoot(document.getElementById('root'));
const persistor = persistStore(store);

const render = () => root.render(
    <React.StrictMode>
        <Provider store={store}>
            <PersistGate loading={null} persistor={persistor}>
                <App />
            </PersistGate>
        </Provider>
    </React.StrictMode>,
    document.getElementById('root'),
);

render()

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals

해당 코드는 이제 세션 스토리지까지 저장하는 방식을 추가한 코드입니다. 기존에는 createStore에는 rootReducer이 들어갔습니다.

 

Redux에 관해서 자세한 내용은 구글링 하니 많이 나오더라고요. 좋은 글들이 많아서 한번 참고해 보시는 거 추천드려요.

 

일정을 등록하는 Modal 페이지 코드 들이에요. 코드가 길어서 style 부분은 지우고 보여드려요.

 

import { format } from 'date-fns'
import React, { useState } from 'react'
import ReactDatePicker from 'react-datepicker'
import { useDispatch, useSelector } from 'react-redux'
import { Button, Divider, Form, Header, Icon, Input, Modal, TextArea } from 'semantic-ui-react'
import { styled } from 'styled-components'
import { add_schedule } from '../reducers/schedule'


const ModalPop = ({schedule}) => {

    const dispatch = useDispatch();
    const [modalPop, setModalPop] = useState(false)
    //제목
    const [scheduleTitle, setScheduleTitle] = useState('')
    // 날짜
    const [changeDate, setChangeDate] = useState('')
    //내용
    const [scheduleCnt, setscheduleCnt] = useState('')
    const changDate = (e) =>{
        return e && setChangeDate(format(e, "yyyy-MM-dd"))
    }

    const handleAddSchedule = () =>{
        dispatch(add_schedule({
            title:scheduleTitle,
            date:changeDate,
            content:scheduleCnt
        }))
        setScheduleTitle('');
        setChangeDate('');
        setscheduleCnt('');
        setModalPop(false)
    }

    const setModalClose = () =>{
        setScheduleTitle('');
        setChangeDate('');
        setscheduleCnt('');
        setModalPop(false)
    }

    
    return (
        <PopupBox>
            <Modal
                onClose={()=>setModalClose()}
                onOpen={()=>setModalPop(true)}
                open={modalPop}
                trigger={<Button>일정 등록</Button>}
                style={{width:"95%", maxWidth:"500px"}}
            >
                <Modal.Header style={{fontFamily:'SUITE-Regular', fontSize:'17px', padding:'15px 20px'}}>일정 등록</Modal.Header>
                <ModalContainer>
                    <Form style={{padding:20, boxSizing:'border-box'}}>
                        <Modal.Content style={{display:'flex', gap:'20px', flexFlow:'row wrap', }}>
                            <Input transparent placeholder="제목" defaultValue={scheduleTitle} onChange={(e)=>setScheduleTitle(e.target.value)} />
                            <ModalCalendar>
                                <Input placeholder={format(new Date(), "yyyy-MM-dd")} readOnly transparent defaultValue={changeDate}  icon={<Icon name="calendar" alternate="true" outline="true" />}  />
                                <ReactDatePicker selected={new Date()} onChange={(date) => changDate(date)} />
                            </ModalCalendar>
                            <TextArea placeholder='내용' style={{ minHeight: 100, width:'100%' }} defaultValue={scheduleCnt} onChange={(e)=>setscheduleCnt(e.target.value)} />
                        </Modal.Content>
                    </Form>
                </ModalContainer>
                <Modal.Actions>
                    <Button color='black' onClick={() => setModalClose()}>취소</Button>
                    <Button
                        content="등록"
                        labelPosition='right'
                        icon='checkmark'
                        onClick={() => handleAddSchedule()}
                        positive
                    />
                </Modal.Actions>
            </Modal>
        </PopupBox>        
    )
}

export default ModalPop

dispath로 add 기능을 가져와서 각각 key와 value의 정보를 전달했어요. 

아까도 말씀드렸지만 action부분 때문에 진짜... 여기 페이지도 썼다 지웠다 썼다 지웠다.

너무 많이 한 거 같아요.

값이 제대로 들어오는지 확인하기 위해 useSelect도 했는데 알고 보니 해당페이지에서 글등록 하고 바로 select을 console로 찍으니 안 나오더라고요.

렌더링 시키기 전에 콘솔을 보여줘서 그런가 싶더라고요. 아니라면 제가 더 공부해 보겠습니다.

 

항상 글을 작성하면서 새로운 방식이 떠오르네요 굳이 내용 초기화 되는 부분을 2개를 쓰지 않고 close를 handleAdd 쪽에 넣으면 초기화되면서 닫히겠네요.

 

이 방식도 글 작성 후 수정해야겠네요.

 

이제 세션에 저 정했던 데이터를 일자별로 해당 일자에 맞는 데이터를 출력시켜주기 위해 CalendarRow 페이지에서 

CalendarItem이라는 컴포넌트를 하나 만들었어요.

 

CalendarItem

import { format } from 'date-fns'
import React from 'react'
import { useSelector } from 'react-redux';
import schedule from './../reducers/schedule';

const CalendarItem = ({itemDate}) => {

    const schedulsDataList = useSelector(state => state.schedule.scheduleList);
    const itemDataCnt = format(itemDate, "yyyy-MM-dd");

    if(schedulsDataList.length > 0){
        return(
            schedulsDataList.map((schedule, i) => {
                // eslint-disable-next-line no-lone-blocks
                {
                    return(
                        schedule.date === itemDataCnt 
                            ? <li key={schedule.keyId}>{schedule.title}</li>
                            :''
                    )
                }
            })
        )
    }
}

export default CalendarItem

제가 적은 저 방식이 괜찮은 방식인지는 모르겠어요. 

저는 개인적으로는 중간에 break를 할 필요가 없고 배열 타입이면 map을 사용하는 게 좋더라고요. 

일정이 있으면 return을 시켜주고 그 일정이 days와 같은 날이면 출력시켜주는 방식으로 했어요.

 

CalendarRow

 

    return (
        <CalendarDaysBox>
            {weekArray.map((week, i)=> (
                <ul className='calendarBox__div days-div' key={i}>
                    {dayArray.map((day, idx)=> (
                        days = addDays(days -1 , 1),
                        <CalendarDays 
                            key={idx}
                            className={
                                `days-div__content ${!isSameMonth(days, monthStart) ? 'ohterMonth' : ''} ${idx === 0 ? 'CalendarDays_sun' : idx === 6 ? 'CalendarDays_sat' : ''} ${Number(format(days, 'd')) === new Date().getDate() && Number(format(days, 'M')) === new Date().getMonth()+1 ? "calendarToday" : '' }`
                            }
                        >
                            <CalendarDay className='days-div__content__span'>
                                <span>{format(days,'dd')}</span>
                                <ul>
                                    <CalendarItem itemDate={days} />
                                </ul>
                            </CalendarDay>
                        </CalendarDays>
                    ))}
                </ul>
            ))}
        </CalendarDaysBox>
    )
}

export default CalendarRow

Row 파일은 item 컴포넌트만 추가하고 날짜만 전달했어요. 

 

글로 작성하니 간단한 기능들인 거 같은데 혼자 엄청 고생을 했는지.... 아직 취업의 길은 엄청 먼 거 같네요.

이럴 때는 왜 퍼블리싱만 하고 프런트로 빨리 전향을 안 했을까 하는 생각이 많이 드네요.....

 

예전에 프런트라는 개발자가 있는 걸 알았더라면 내가 IT 쪽에 관심이 더 많았더라면 오늘따라 조금 후회가 되네요

하지만 후회하면 얻는 게 없으니 더 많이 공부해서 빨리 프론트로 이직할 수 있게 노력하려고요.

 

오늘은 미래의 목표를 위한 한 걸음 이니깐요.

 

그럼 주말 잘 보내시고 다음 주 평일에 다시 올게요~~

728x90
반응형