profile image

L o a d i n g . . .

전 / 후

글작성과 수정이 겹치는 부분이 많아서 DiaryEditor 컴포넌트를 따로 만들었다 

 

import DiaryEditor from "../components/DiaryEditor"

const New = () => {
    return (
        <div>
            <DiaryEditor />
        </div>
    )
};

export default New;

그리고 New컴포넌트에서 DiaryEditor를 불러와주었따

 

 

 

 

 

 

 

 


헤더 만들기

 

import { useNavigate } from "react-router-dom";

import MyHeader from "./components/MyHeader"
import MyButton from "./components/MyButton"


const DiaryEditor = () => {

    const navigate = useNavigate();

    return (
        <div>
            <MyHeader
                headText={"새 일기 쓰기"}
                leftChild={<MyButton text={"< 뒤로가기 "} onClick={() => navigate(-1)} />}
            />
        </div>
    );
};

export default DiaryEditor;

미리 만들어둔 헤더 컴포넌트를 부르고 뒤로가기 왼쪽엔 버튼을 수행할 MyButton 컴포넌트를 가지고온다.

그리고 뒤로가기가 실제로 수행이 되도록 useNavigate함수를 통해 뒤로가기 기능을 넣어주었다

 

 

 

 

 

 

 

 

 

 


날짜 선택 부분 구현하기

 

const DiaryEditor = () => {
    const [date, setDate] = useState();
    const navigate = useNavigate();

    return (
        <div>
            <MyHeader
                headText={"새 일기 쓰기"}
                leftChild={<MyButton text={"< 뒤로가기 "} onClick={() => navigate(-1)} />}
            />
            <div>
                <section>
                    <h4>오늘은 언제인가요?</h4>
                    <div className="input-box">
                        <input value={date} onChange={(e) => setDate(e.target.value)} type={"date"} />
                    </div>
                </section>
            </div>
        </div>
    );
};

input 타입을 date로 지정해주면 달력모양 input태그가 생성된다

값을 저장하기위해 상태변화함수 useState를 임포트 해주고 date를 담을 useState함수를 넣어 onChange이벤트를 준다

 

 

 

 

 

 

mount 됐을때 오늘의 날짜로 기본 설정  

const getStringDate = (date) => {
    let year = date.getFullYear();
    let month = date.getMonth() + 1;
    let day = date.getDate();
    if (month < 10) {
        month = `0${month}`;
    }

    if (day < 10) {
        day = `0${day}`;
    }
    return `${year}-${month}-${day}`;
}

getStringDate 상수를 만들어준 후 useState 함수 안에 넣어 초기값을 주었다

 

 

Date.prototype.toISOString() - JavaScript | MDN

toISOString() 메서드는 단순화한 확장 ISO 형식(ISO 8601)의 문자열을 반환합니다. 반환값은 언제나 24글자 또는 27글자(각각 YYYY-MM-DDTHH:mm:ss.sssZ 또는 ±YYYYYY-MM-DDTHH:mm:ss.sssZ)입니다. 시간대는 언제나 UTC

developer.mozilla.org

 

toISOString함수는 날짜를 ISO8601형식의 문자열로 반환해주는 함수

 

오늘의 날짜가 잘 나타나는것을 확인할 수 있다

 

 

 

 

 


본문 전 CSS 추가

 

/* DiaryEditor */

.DiaryEditor section {
  margin-bottom: 40px;
}

.DiaryEditor h4 {
  font-size: 22px;
  font-weight: bold;
}

.DiaryEditor .input_date {
  border: none;
  border-radius: 5px;
  background-color: #ececec;
  padding: 10px 20px;
  cursor: pointer;
  font-family: "Nanum Pen Script";
  font-size: 20px;
}

 

 

 


본문 감정 이미지 넣기

 

const env = process.env;
env.PUBLIC_URL = env.PUBLIC_URL || "";

const emotionList = [
    {
        emotion_id: 1,
        emotion_img: process.env.PUBLIC_URL + `/assets/emotion1.png`,
        emotion_descript: '신남'
    },
    {
        emotion_id: 2,
        emotion_img: process.env.PUBLIC_URL + `/assets/emotion2.png`,
        emotion_descript: '좋음'
    },
    {
        emotion_id: 3,
        emotion_img: process.env.PUBLIC_URL + `/assets/emotion3.png`,
        emotion_descript: '보통'
    },
    {
        emotion_id: 4,
        emotion_img: process.env.PUBLIC_URL + `/assets/emotion4.png`,
        emotion_descript: '나쁨'
    },
    {
        emotion_id: 5,
        emotion_img: process.env.PUBLIC_URL + `/assets/emotion5.png`,
        emotion_descript: '끔찍'
    },
]

이미지를 넣기위한 링크객체를 배열로 만들고

const EmotionItem = ({ emotion_id, emotion_img, emotion_descript }) => {
    return (
        <div className="EmotionItem">
            <img src={emotion_img} />
            <span>{emotion_descript}</span>
        </div>
    )
}

export default EmotionItem;

EmotionItem컴포넌트를 만들어 분리시켜준 후

 

 

 

 

                <section>
                    <h4>오늘의 감정</h4>
                    <div className="input_box emotion_list_wrapper">
                        {emotionList.map((it) => (
                            < EmotionItem key={it.emotion_id}{...it} />
                        ))}
                    </div>
                </section>

컴포넌트 리턴내에 두번째 색션을 만들어주었따 

 

 

.DiaryEditor .emotion_list_wrapper {
  display: grid;
  grid-template-columns: repeat(5, auto);
  gap: 2%;
}

/* EmotionItem */

.EmotionItem {
  cursor: pointer;
  border-radius: 5px;
  padding: 20px 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.EmotionItem img {
  width: 50%;
  margin-bottom: 10px;
}

.EmotionItem span {
  font-size: 18px;
}

 

 

 

 

 

선택된 이미지 효과 넣기

    const [emotion, setEmotion] = useState(3);

    const handleClickEmote = (emotion) => {
        setEmotion(emotion);
    }

다이어리 에디터에 이모션을 관리할 수 있는 상태와 hadleClickEmote 상수를 만들어준다.

 

 

const EmotionItem = ({
    emotion_id,
    emotion_img,
    emotion_descript,
    onClick,
    isSelected,
}) => {
    return (
        <div
            onClick={() => onClick(emotion_id)}
            className={[
                "EmotionItem",
                isSelected ? `EmotionItem_on_${emotion_id}` : `EmotionItem_off`,
            ].join(" ")} >
            <img src={emotion_img} />
            <span>{emotion_descript}</span>
        </div >
    )
}

이모션아이템 컴포넌트에 클릭시 변화될 상태props을 추가하고 태그를 넣어주었다

 

 

 

                        {emotionList.map((it) => (
                            < EmotionItem
                                onClick={handleClickEmote}
                                key={it.emotion_id}
                                {...it}
                                isSelected={it.emotion_id === emotion}
                            />
                        ))}

다이어리에디터 이모션 리턴부분에 onClick이벤트랑 isSelected 이벤트도 넣어주었다.

 

 

.EmotionItem_off {
  background-color: #ececec;
}

.EmotionItem_on_1 {
  background-color: #64c964;
  color: white;
}

.EmotionItem_on_2 {
  background-color: #9dd772;
  color: white;
}

.EmotionItem_on_3 {
  background-color: #fdce17;
  color: white;
}

.EmotionItem_on_4 {
  background-color: #fd8446;
  color: white;
}

.EmotionItem_on_5 {
  background-color: #fd565f;
  color: white;
}

그리고 CSS까지 넣으면

 

 

클릭했을때 isSelect 속성에 맞추어 태그이름이 변화하고 그에 맞춰 css속성이 들어간다

 

 

 

 

 

 

 

 


일기 작성란 만들기

    const contentRef = useRef();
    const [content, setContent] = useState("");

다이어리 에디터 컴포넌트 내에 컨텐츠 state를 만들고 관리할 수 있는 useRef를 임포트해준다.

 

 

 

 

 

                <section>
                    <h4>오늘의 일기</h4>
                    <div className="input_box text_wrapper">
                        <textarea
                            placeholder="오늘은 어땠나요?"
                            ref={contentRef}
                            value={content}
                            onChange={(e) => setContent(e.target.value)} />
                    </div>
                </section>

세번째 섹션을 만들어주고

 

 

css까지 적용해주면

.DiaryEditor textarea {
  font-family: "Nanum Pen Script";
  font-size: 20px;

  box-sizing: border-box;
  width: 100%;
  min-height: 200px;
  resize: vertical;

  border: none;
  border-radius: 5px;
  background-color: #ececec;
  padding: 20px;
}

일기작성 완성

 

 

 

 

 

 


하단버튼 

 

 

                <section>
                    <div className="control_box">
                        <MyButton text={"취소하기"} onClick={() => navigate(-1)} />
                        <MyButton
                            text={"작성완료"}
                            type={"positive"}
                            onClick={handleSubmit} />
                    </div>
                </section>

마지막섹션! 

    const { onCreate } = useContext(DiaryDispatchContext);

	const handleSubmit = () => {
        if (content.length < 1) {
            contentRef.current.focus();
            return;
        }

        onCreate(date, content, emotion);
        navigate("/", { replace: true });
    }

 

 

 

 

값을 확인해보니 Context에만 들어오고 State는 업데이트가 안되고 있어서 엄청찾았는데..

dispatch 에 들어갈 data의 date가....

data로 적혀있었다

 

하.. 오타조심하자 에러도 안뿜어준다 ㅠㅠㅠㅠㅠㅠ

 

 

 

data안에 들어갈 값을 잘 지정해주니.. 아주 잘들어간다 ;-;

 

 

 

 

 

 

참고 :

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

반응형
복사했습니다!