diaryPage 에 대략적인 퍼블리싱을 만들어 보았다
-> 어떤것을 써야 글이 써질까 생각하다가, 게시판에 자주 쓰이는
"textarea" 라는 기능을 쓰기로 정하였다.
🚩textarea는 여러 줄의 긴 문장을 입력할 수 있는 양식이다.
🚩 사용방법: < textarea >< /textarea >
-> textarea 태그를 추가해 주었다. 그후,
입력 type 과 name 값을 입력해 주었다.
📁5Page
L 📁components
L diaryForm.js
<PostForm>
<textarea
type="text"
placeholder="일기내용을 작성해주세요"
name='content'
/>
</PostForm>
-> css 추가
const PostForm = styled.form`
width: auto;
height: auto;
margin: 0 auto;
padding: 20px;
& textarea {
resize: none;
width: 95%;
height: 190px;
font-family: 'SB 어그로 L';
border: none;
padding: 15px 15px;
::-webkit-scrollbar {
width: 8px;
background-color: red;
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
width: 8px;
background-color: blue;
border-radius: 10px;
}
:focus {
outline: none;
}
}
📍textarea css 에서 신경섰던 부분이 있었는데 입력 text 가 길어질때,
스크롤이 생기면서 아래로 이어져서 써져야 하는것이였다. 따라 css 에
2가지의 기능을 넣어주었다.
::-webkit-scrollbar
의 기능은 전체 스크롤바. 를 뜻하는 것이다.
::-webkit-scrollbar-thumb 는 드래그 가능한 스크롤 핸들. 을 나타낸다.
이해하기 쉽도록 이미지를 붙여 본다.
내용이 입력 될때마다 변경된 내용에 대해 나타나 줘야 하기 때문에 onChange의 이벤트를 추가해주었다.
🚩 onchange 이벤트는 요소의 값이 변경되었을 때 발생한다.
📁5Page
L 📁components
L diaryForm.js
const DiaryForm = () => {
const [ViewData, setViewData] = useState({
id:""
,title:""
,content:""
,date: new Date()
,color:""
})
const getChangeContent = (e) => {
const{name, value} = e.target;
console.log(name, value);
setViewData({
...ViewData,
[name]:value
})
console.log(ViewData);
};
return(
<>
<PostForm>
<textarea
type="text"
placeholder="일기내용을 작성해주세요"
name='content'
onChange={getChangeContent}
/>
</PostForm>
</>
);
};
-> useState({}) 안에 들어갈 데이터들을 넣어두었다.
[필요한 기본 데이터들 = 글id, 글제목, 글내용, 등록날짜, 다이어리컬러값]
맨 처음에는 id, title, content, date, color 데이터 값들이 비어있기 때문에 빈 값 "" 으로 넣어두었다.
-> state 를 이용하여 들어갈 data 들을 ViewData, 에 넣어두었고 입력 상태가 바뀔때마다, setViewData에 [name] :value 값을 추가하여 저장된다. console.log(ViewData) 콘솔을 출력해 보면, 입력할때마다 추가된 모습이 보인다.
🤔 다이어리를 입력 할때의 날짜가 언제인지 날짜표시에 대한 기능을
만들어야 한다. react 날짜표시 기능을 찾아보니, react-datepicker 는 라이브러리가 있었고 이것을 이용해서 날짜를 표시해 보기로 하였다. 설치 방법부터 적어놓으려니 적어질것 같아 따로 포스팅을 해두었다.
datepicker 를 적용하는 방법
📍 datePicker 적용후 전체 코드
📁5Page
L 📁components
L diaryForm.js
import styled from "styled-components";
import DatePicker from "react-datepicker";
import { useState, forwardRef } from 'react';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCircleArrowLeft, faCircleCheck } from "@fortawesome/free-solid-svg-icons"
const DiaryForm = () => {
const [ViewData, setViewData] = useState({
id:""
,title:""
,content:""
,date: new Date()
,color:""
})
const DatePick = forwardRef(({ value, onClick }, ref) => (
<Datebutton className='custom-btn'
onClick={onClick} ref={ref}>
{value}
</Datebutton> ));
const getChangeContent = (e) => {
const{name, value} = e.target;
console.log(name, value);
setViewData({
...ViewData,
[name]:value
})
console.log(ViewData);
};
return(
<>
<AllDiaryBox>
<DiaryContainer>
<PostTitle>
<Datebox>
<DatePicker
//value={date}
dateFormat="yyyy-MM-dd"
selected={ViewData.date}
onChange={(date) => setViewData({
...ViewData,
'date': date,
})}
customInput={<DatePick/>}
/>
</Datebox>
<div className='inputBox'>
<input
type="text"
placeholder="제목을 작성해주세요"
name='title'
/>
</div>
<FontAwesomeIcon
type='button'
className="CheckIcon"
icon={faCircleCheck}
/>
<FontAwesomeIcon
type='button'
className="beforeIcon"
icon={faCircleArrowLeft}
/>
</PostTitle>
<WriteInnerBox>
<PostForm>
<textarea
type="text"
placeholder="일기내용을 작성해주세요"
name='content'
onChange={getChangeContent}
//value={content}
/>
</PostForm>
</WriteInnerBox>
</DiaryContainer>
<DiaryInnerBox>
</DiaryInnerBox>
</AllDiaryBox>
</>
);
};
export default DiaryForm;
const AllDiaryBox = styled.div`
width: 800px;
position: relative;
height: 800px;
z-index: 10;
`
const DiaryContainer = styled.div`
max-width: 676px;
max-height: 400PX;
margin: 0 auto;
margin-top: 10px;
border-radius: 15px;
background-color: #5800FF;
justify-content: center;
padding: 27px;
`
const PostTitle = styled.div`
width: 670px;
height: 50px;
display: flex;
position: relative;
align-items: center;
justify-content: end;
margin-bottom: 10px;
left: 10px;
& p {
margin-right: 30px;
text-align: center;
font-size: 18px;
color: white;
font-family: 'SB 어그로 M';
}
& .inputBox{
width: 300px;
height: 40px;
border-radius: 20px;
background-color: white;
display: flex;
position: relative;
align-items: center;
padding: 0 20px;
margin-right: 10px;
right: 60px;
& input {
width: 100%;
font-family: 'SB 어그로 L';
border: none;
:focus {
outline: none;
}
}
}
& .CheckIcon {
width: 50px;
height: 35px;
color: white;
position: relative;
display: flex;
right: 50px;
}
& .beforeIcon{
display: flex;
position: relative;
width: 35px;
height: 35px;
border-radius: 50px;
color: white;
right: 40px;
}
`
const Datebox = styled.div`
width: 140px;
height: 40px;
position: relative;
display: flex;
right: 70px;
`
const Datebutton = styled.button`
width: 110px;
height: 40px;
border: none;
border-radius: 30px;
background-color: #8D72E1;
color: white;
:hover{
background-color: #8D9EFF;
}
`
const WriteInnerBox = styled.div`
width: 100%;
height: 260px;
border-radius: 10px;
margin: 0 auto;
`
const PostForm = styled.form`
width: auto;
height: auto;
margin: 0 auto;
padding: 20px;
& textarea {
resize: none;
width: 95%;
height: 190px;
font-family: 'SB 어그로 L';
border: none;
padding: 15px 15px;
::-webkit-scrollbar {
width: 8px;
background-color: #F4F4F4;
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
width: 8px;
background-color: #c4c4c4;
border-radius: 10px;
}
:focus {
outline: none;
}
}
`
const DiaryInnerBox = styled.div`
width: 676px;
height: 310px;
margin: 0 auto;
background-color: #CED0E9;
overflow: hidden;
margin-top: 50px;
`
🍀적용 결과🍀
-> 현재 날짜가 보여지는것을 볼수 있다.
🤔 생각해보기
-> 5가지의 color 값이 있는데, 각각 클릭할때마다 배경색이 바뀌어야 한다.
🍀상태관리 라이브러리로 recoil를 사용한 이유🍀
-> 클릭할때마다 상태값이 바뀌어야 하기때문에, 상태관리 라이브러리인 redux 를 사용 하려 했다. 하지만 아직 초보인 나에게는 빠른시간내에 쉽게 적용해볼수 있는 라이브러리가 유용하다 판단하여 recoil 을 사용해 보기로 하였다.
📍color 설정
📁resource
L color.js
export const Color = {
"설렘": "#FFCCCC",
"슬픔": "#7A90E2",
"기쁨": "#FFDF78",
"화남": "#E5636F",
"무기력": "#C4C4C4",
};
-> 색상 정보들을 Color 라는 변수 안에다가 넣어주었다.
📍 recoil 사용법
npm install recoil
return (
<div className="App">
<>
<RecoilRoot>
<Routes>
<Route path="/" element={
<PrivateRoute component={<ThirdPage/>} status={<Onepage/>}/>
}/>
<Route path="/twopage" element={<TwoPage/>} />
<Route path="/thirdpage" element={
<PrivateRoute component={<ThirdPage/>}/>
}/>
<Route path="/fourpage" element={
<PrivateRoute component={<Fourpage/>}/>
}/>
<Route path="/fivepage" element={
<PrivateRoute component={<Fivepage/>} />
}/>
</Routes>
</RecoilRoot>
</>
</div>
);
-> recoil을 다운받은후 , App.js 에다가 recoilRoot로 감싸주었다.
📍 상태값 선언
📁recoil
L colorState.js
import { atom } from "recoil";
const initialState = {
color: "#5800FF"
};
export const recoilColorState = atom({
key: "recoilColorState",
default: initialState
});
-> Atoms는 어떤 컴포넌트에서나 읽고 쓸 수 있다. atom의 값을 읽는 컴포넌트들은 암묵적으로 atom을 구독한다. 그래서 atom에 어떤 변화가 있으면 그 atom을 구독하는 모든 컴포넌트들이 재 렌더링 되는 결과가 발생할 것이다.
📁5Page
L 📁components
L colorForm.js
import styled from "styled-components";
import { useState, useEffect } from 'react';
import { Color } from "../../resource/color.js"
import { useRecoilState } from "recoil";
import {recoilColorState} from "../../recoil/colorState"
const ColorForm = () => {
const [recoilColor, setRecoilColor] = useRecoilState(recoilColorState);
const defaultColor = { ...recoilColor};
const colorArray = Object.values(Color);
const colorNameArray = Object.keys(Color);
const [colorState, setColorState] = useState(defaultColor.color);
const onColorChangeHandler = (color) => {
setColorState(color);
};
useEffect(() => {
const changedColor = {
color: colorState
};
setRecoilColor(changedColor);
}, [colorState]);
return (
<>
<WhiteContainer>
<p className="titleText">오늘의 기분은 어떤 색인가요?</p>
<ColorPallete>
{colorArray.map((color,index) => (
<ColorCircle key={color} background={color}>
<label for={color}></label>
<input
type="radio"
id={color}
checked={colorState === color}
onChange={() => onColorChangeHandler(color, index)}
/>
<p>{colorNameArray[index]}</p>
</ColorCircle>
))}
</ColorPallete>
</WhiteContainer>
</>
);
};
export default ColorForm;
const WhiteContainer = styled.div`
width: 676px;
height: 106px;
background-color: #CED0E9;
display: inline-block;
margin: 0 auto;
position: relative;
left: 50px;
font-family: 'SB 어그로 L';
& .titleText {
text-align: center;
margin-top: 25px;
color: white;
font-size: 17px;
}
`
const ColorPallete = styled.ul`
width: 80%;
margin: 0 auto;
display: flex;
gap: 30px;
`;
const ColorCircle = styled.li`
list-style-type: none;
display: flex;
align-items: center;
gap: 10px;
& > label {
display: inline-block;
background-color: ${(props) => props.background};
width: 30px;
height: 30px;
border-radius: 100%;
cursor: pointer;
transition: all 0.25s;
}
& > label:hover {
transform: scale(1.15);
}
& > input {
display: none;
}
`;
-> state 기본 값으로 useRecoilState(recoilColorState)
colorState 파일에 선언해둔 (recoilColorState) 값을 넣어두었고
defaultColor 라는 변수에 기본 값을 복사해둔 { ...recoilColor} 값을 선언하였다.
-> const colorArray = Object.values(Color);
const colorNameArray = Object.keys(Color);
Object.values() 메서드를 사용해
Color 값 과, Color의 이름을 배열화 하였다.
Object.values()정적 메서드는 주어진 개체 자체의 열거 가능한 문자열 키 속성 값의 배열을 반환한다.
-> colorState 값으로 위에 기본값으로 복사해둔 useState(defaultColor.color) 을 기본값으로 지정해두었다.
-> map()을 사용하여 위에 새로운 colorArray 값을 배열을 만들었다.
<ColorCircle 안에 key 값으로 {color}를 넣어 주었고, background 에도 = {color} 값을 넣어주었다.
-> 각각의 color 값을 label 을 이용해서 나타내 주었다.
"label for" 라는 태그를 써주었는데 ,
input 태그를 제어하여 상태를 변경하도록 도와주는 태그 이다.
즉, 클릭의 유효범위가 달라진다.
사용하기 위해서는 input 태그의 id와 같아야 한다.
-> 따라, 아래와 같이 input 태그 안에 label 과 같은 id값을 넣어 주었고 , color 값이 바뀔때마다 새로운
setColorState(color) 값으로 나타난다.
-> & > label {
background-color: ${(props) => props.background};
label의 color 값을 porps 로 넘겨주었다.
{colorArray.map((color,index) => (
<ColorCircle key={color} background={color}>
<label for={color}></label>
<input
type="radio"
id={color}
checked={colorState === color}
onChange={() => onColorChangeHandler(color, index)}
/>
<p>{colorNameArray[index]}</p>
</ColorCircle>
))}
-> useEffect 처음 기본 color값을 : colorState 로 지정해주고, 변경된 값을 setRecoilColor(changedColor) 로 넣어준다.
,그리고 [colorState]가 업데이트 될때마다, 반복 되서 실행된다.
📁5Page
L 📁components
L diaryForm.js
import { useState, forwardRef, useEffect } from 'react';
import { recoilColorState } from "../../recoil/colorState";
import { useRecoilState } from "recoil";
import './diary.css'
const DiaryForm = () => {
const [recoilColor, setRecoilColor] = useRecoilState(recoilColorState);
const defaultColor = { ...recoilColor };
const [colorPeeker, setColorPeeker] = useState(defaultColor.color);
}
useEffect(() => {
const tmpColor = { ...recoilColor };
setColorPeeker(tmpColor.color);
},[recoilColor]);
return(
<DiaryContainer background={colorPeeker}>
)
};
export default DiaryForm;
const DiaryContainer = styled.div`
max-width: 676px;
max-height: 400PX;
margin: 0 auto;
border-radius: 15px;
background-color: ${(props) => props.background};
justify-content: center;
padding: 27px;
`
-> 위와 똑같이
useRecoilState 에 기본값으로 (recoilColorState) 을 지정해두었고,
defaultColor 변수에 복사된 { ...recoilColor } 값을 넣어두었다.
color의 새 state 값을 지정해두고 기본값으로 (defaultColor.color) 를 지정해두었다.
const [colorPeeker, setColorPeeker] = useState(defaultColor.color);
-> [recoilColor] 값이 업데이트 될때마다,
useEffect 안에 있는 함수들이 반복되서 실행된다.
-> <DiaryContainer 의 배경 색을 state 값 background={colorPeeker} 로 넣어 주었고
css 에 background-color: ${(props) => props.background};
props를 사용하여 선택한 color 값으로 바뀌게 끔 구현하였다.
🍀최종 결과🍀
다이어리 등록은 다음글에 포스팅 하겠다.