profile image

L o a d i n g . . .

수정 전/ 후 홈 모습

 

 

 

 

 

 

날짜헤더 등록하기

mount가 됨과 동시에 날짜가 표시되어야 하고 월을 이동할 버튼이 필요함

 

import { useState } from "react";
import MyHeader from './../components/MyHeader'

const Home = () => {

    const [curDate, setCurDate] = useState(new Date());

    const headText = `${curDate.getFullYear()}년 ${curDate.getMonth() + 1}월`

    return (
        <div>
            <MyHeader headText={headText} />
        </div>
    );
};

export default Home;

useState를 통해 날짜를 set해준다.

전에 헤더로 만들어두었던 MyHeader 컴포넌트를 import 해주고

MyHeader컴포넌트 중 headrText안에 headText를 추가해준다.

 

 

headText 년 월 설정 시 주의사항

JS에서 월은 0부터 시작되므로 +1을 해줘야한다

 

 

 

 


 

 

 

 

헤더 버튼 구현하기

const Home = () => {
    const [curDate, setCurDate] = useState(new Date());
    const headText = `${curDate.getFullYear()}년 ${curDate.getMonth() + 1}월`
    const increaseMonth = () => {
        setCurDate(new Date(curDate.getFullYear(), curDate.getMonth() + 1, curDate.getDate()));
    }
    const decreaseMonth = () => {
        setCurDate(new Date(curDate.getFullYear(), curDate.getMonth() - 1, curDate.getDate()));
    }

    return (
        <div>
            <MyHeader
                headText={headText}
                leftChild={<MyButton text={"<"} onClick={decreaseMonth} />}
                rightChild={<MyButton text={">"} onClick={increaseMonth} />}
            />
        </div>
    );
};

버튼도 저번에 만들어둔 버튼 컴포넌트를 불러와주었다.

MyHeader 왼쪽 오른쪽에 MyButton컴포넌트를 넣어주고 달이 추가될 때와 이전달로 돌아갈 때 필요한 함수를 작성해 onClick 이벤트로 넣어주었다

 

 

 

 

 

 

 

 

 

 


DiaryList 만들기

 

일단 리스트에 출력할 내용이 비어있어서 더미데이타를 넣어주었다 

 

const dummyData = [
  {
    id: 1,
    emotion: 1,
    content: "오늘의 일기 1번",
    date: 1659698205892
  },
  {
    id: 2,
    emotion: 3,
    content: "오늘의 일기 2번",
    date: 1659698205893
  },
  {
    id: 3,
    emotion: 3,
    content: "오늘의 일기 3번",
    date: 1659698205894
  },
  {
    id: 4,
    emotion: 4,
    content: "오늘의 일기 4번",
    date: 1659698205895
  },
  {
    id: 5,
    emotion: 5,
    content: "오늘의 일기 5번",
    date: 1659698205896
  },
]

 

기존에는 [] 빈배열이었던 data의 초기값을 dummyData로 바꿔준다.

 

 

 

 

 

 

    const diaryList = useContext(DiaryStateContext);

이후 Home 컴포넌트에서  Provider를 통해 해당 더미데이터를 전달받는다 

 

 

 

정상적으로 일기 5개를 전달받은 모습을 확인 할 수 있다

 

 

 

 

 

이제 날짜에 따라 해당되는 일기만 뜨게 설정해보자

 

    const [data, setData] = useState([]);

    useEffect(() => {
        if (diaryList.length >= 1) {
            const firstDay = new Date(
                curDate.getFullYear(),
                curDate.getMonth(),
                1
            ).getTime();

            const lastDay = new Date(
                curDate.getFullYear(),
                curDate.getMonth() + 1,
                0
            ).getTime();

            setData(
                diaryList.filter((it) => firstDay <= it.date && it.date <= lastDay)
            );
        }
    }, [diaryList, curDate]);

    useEffect(() => {
        console.log(data);
    }, [data]);

if문으로 diary에 값이 있을때만 data를 이용해 해달 달에 위치한 diaryList만 추려서 출력되게 해주었다

 

 

 

 

임시데이터가 오늘날짜로 되어있기때문에 8월에 해당할때만 출력된다.

 

 

 


Home안에 들어갈 DiaryList 컴포넌트 생성

 

props로 diaryList를 받는 DiaryList 컴포넌트를 만들었다.

const DiaryList = ({ diaryList }) => {
    return (
        <div>
            {diaryList.map((it) => (
                <div key={it.id}>{it.content}</div>
            ))}
        </div>
    )
}

DiaryList.defaultProps = {
    diaryList: [],
}

export default DiaryList;

map으로 list랜더링을 해주었다.

 

그리고다시 Home 컴포넌트로 돌아와 import 후 자식으로 추가해주었다.

 

 

 

 

 

 

 


List에 정렬기능 추가

const sortOptionList = [
    { value: "latest", name: "최신순" },
    { value: "oldest", name: "오래된 순" },
]

const ControlMenu = ({ value, onChange, optionList }) => {
    return <select value={value} onChange={(e) => onChange(e.target.value)}>
        {optionList.map((it, idx) => (
            <option key={idx} value={it.value}>
                {it.name}
            </option>
        ))}
    </select>
}

const DiaryList = ({ diaryList }) => {

    const [sortType, setSortType] = useState('latest');

    const getProcessedDiaryList = () => {
        const compare = (a, b) => {
            if (sortType === 'latest') {
                return parseInt(b.date) - parseInt(a.date);
            } else {
                return parseInt(a.date) - parseInt(b.date);
            }
        }
        const copyList = JSON.parse(JSON.stringify(diaryList));
        const sortedList = copyList.sort(compare);
        return sortedList;
    };

    return (
        <div>
            <ControlMenu
                value={sortType}
                onChange={setSortType}
                optionList={sortOptionList} />
            {getProcessedDiaryList().map((it) => (
                <div key={it.id}>{it.content}</div>
            ))}
        </div>
    )
}

 

옵션리스트를 통해 최신순, 오래된순으로 값을 주고  값이 변화할 때 Change이벤트를 optionList에 준다.

 

최신순 오래된순 정렬은 sort대신 JSON.parse(JSON.stringify()) 를 사용해 깊은 복사를 해줄것이다.

 

후 DiaryList에 map으로 list랜더링을 해주는게아닌 getProcessedDiaryList를 랜더링을 해주어 최신, 오래된 순으로 상태변화를 할 수 있도록 해주었다.

 

 

 

 

 

 

 

 

 


감정필터링 추가

 

 

 

    const [filter, setFilter] = useState("all");

DiaryList 컴포넌트안에 filter를 추가해주었다

 

 

const filterOptionList = [
    { value: "all", name: "전부 다" },
    { value: "good", name: "좋은 감정만" },
    { value: "bad", name: "안좋은 감정만" },
]

select에 나타날 옵션의 name을 정렬때처럼 따로 만들어주었다

 

            <ControlMenu
                value={filter}
                onChange={setFilter}
                optionList={filterOptionList} />

DiaryList 컴포넌트 return 안에 정렬 때와 똑같이 필터링 값, 변경값, 변경요소를 적어주었다. 

 

 

 

    const getProcessedDiaryList = () => {

        const filterCallback = (item) => {
            if (filter === 'good') {
                return parseInt(item.emotion) <= 3;
            } else {
                return parseInt(item.emotion) > 3;
            }
        }

        const compare = (a, b) => {
            if (sortType === 'latest') {
                return parseInt(b.date) - parseInt(a.date);
            } else {
                return parseInt(a.date) - parseInt(b.date);
            }
        }
        const copyList = JSON.parse(JSON.stringify(diaryList));
        const filteredList = filter === 'all' ? copyList : copyList.filter((it) => filterCallback(it));
        const sortedList = filteredList.sort(compare);
        return sortedList;
    };

랜더링 되는 필터링에 filteredList를 추가해서 감정값에따라 필터링 된 후 정렬되도록 하였다.

 

 

 

 

 

 

 

 

 


새일기쓰기 버튼 생성

 

 

react router dom의 navigator를 사용해 새 일기쓰기 버튼을 누르면 /new url로 이동하도록 해주었다.

<MyButton type={'positive'} text={'새 일기쓰기'} onClick={() => navigate("/new")} />

 

 

 

 

 


menu css

각 디비전에 className부여 해주고 

/* DiaryList */

.DiaryList .menu_wrapper {
  margin: 20px 0 30px 0;
  display: flex;
  justify-content: space-between;
}

.DiaryList .menu_wrapper .right_col {
  flex-grow: 1;
}

.DiaryList .menu_wrapper .right_col button {
  width: 100%;
}

.DiaryList .ControlMenu {
  margin-right: 10px;
  border: none;
  border-radius: 5px;
  background-color: #ececec;
  padding: 10px 20px;
  cursor: pointer;
  font-family: "Nanum Pen Script";

 

 

 

 

 

 


다이어리 아이템  만들기

현재 오늘의 일기가 뿌려지는 부분은 저 부분이다. 

 

            {getProcessedDiaryList().map((it) => (
                <DiaryItem key={it.id} {...it} />
            ))}

랜더링 될 부분을 DiaryItem 컴포넌트로 바꿔준다. 

 

            <div className={[
                "emotion_img_wrapper",
                `emotion_img_wrapper_${emotion}`,
            ].join(" ")}
            >
                <img src={process.env.PUBLIC_URL + `assets/emotion${emotion}.png`} />
            </div>

첫번째 디비전은 이미지가 들어오는 감정표현 emotion부분

 

 

/* DiaryItem */
.DiaryItem {
  padding: 15px 0;
  border-bottom: 1px solid #e2e2e2;
  display: flex;
  justify-content: space-between;
}

.DiaryItem .emotion_img_wrapper {
  cursor: pointer;
  min-width: 120px;
  height: 80px;
  border-radius: 5px;
  display: flex;
  justify-content: center;
}

.DiaryItem .emotion_img_wrapper_1 {
  background-color: #64c964;
}

.DiaryItem .emotion_img_wrapper_2 {
  background-color: #9dd772;
}

.DiaryItem .emotion_img_wrapper_3 {
  background-color: #fdce17;
}

.DiaryItem .emotion_img_wrapper_4 {
  background-color: #fd8446;
}

.DiaryItem .emotion_img_wrapper_5 {
  background-color: #fd565f;
}

.DiaryItem .emotion_img_wrapper img {
  width: 50%
}

CSS까지 추가해주면

 

귀요미 감정표현들이 들어가있다 

emotion 점수에 따라 달라지는 이미지!

 

 

 

 

 

 

두번째 디비전은 날짜와 본문미리보기 부분

    const strDate = new Date(parseInt(date)).toLocaleDateString();
            <div className="info_wrapper">
                <div className="diary_date">{strDate}</div>
                <div className="diary_content_priview">{content.slice(0, 25)}</div>
            </div>

날짜는 현재 ms로 나오고 있어서 보기편하게 localeDateString함수를 사용하여 변환해주었다. 

 

 

.DiaryItem .info_wrapper {
  flex-grow: 1;
  margin-left: 10px;
  cursor: pointer;
}

.DiaryItem .diary_date {
  font-weight: bold;
  font-size: 25px;
  margin-bottom: 5px;
}

.DiaryItem .diary_content_priview {
  font-size: 18px;
}

CSS까지 완료

 

 

 

 

 

 

두번째 디비전은 수정하기 버튼

            <div className="btn_wrapper">
                <MyButton text={"수정하기"} />
            </div>
.DiaryItem .btn_wrapper {
  min-width: 70px;
}

 

 

 

 

마지막! navigator를 사용해서 url 입력하기

import { useNavigate } from "react-router-dom";
import MyButton from "./MyButton";

const DiaryItem = ({ id, emotion, content, date }) => {
    const navigate = useNavigate();
    const strDate = new Date(parseInt(date)).toLocaleDateString();
    const goDetail = () => {
        navigate(`/diary/${id}`);
    }
    return (
        <div className="DiaryItem">
            <div onClick={goDetail} className={[
                "emotion_img_wrapper",
                `emotion_img_wrapper_${emotion}`,
            ].join(" ")}
            >
                <img src={process.env.PUBLIC_URL + `assets/emotion${emotion}.png`} />
            </div>
            <div onClick={goDetail} className="info_wrapper" >
                <div className="diary_date">{strDate}</div>
                <div className="diary_content_priview">{content.slice(0, 25)}</div>
            </div>
            <div className="btn_wrapper">
                <MyButton text={"수정하기"} onClick={() => navigate(`/edit/${id}`)} />
            </div>
        </div>
    )
}

export default DiaryItem;

수정하기 버튼은 MyButton에 onClick 이벤트가 있기때문에 goDetail처럼 함수로 따로 안빼고 그냥 넣어줬다

 

 

 

 

 

 

 


Home 페이지 완성

 

 

 

 

 

참고 :

-  한 입 크기로 잘라먹는 리액트

반응형
복사했습니다!