component
import { RefObject } from "react";
import { CounterState } from "../../../../store/types/state";
import { da } from "../../../../type";
const Modify = ({
titleref,
dateref,
timeref,
addressref,
contentref,
tagsref,
finish,
reset,
main,
id,
}: {
titleref: RefObject<HTMLInputElement>;
dateref: RefObject<HTMLInputElement>;
timeref: RefObject<HTMLInputElement>;
addressref: RefObject<HTMLInputElement>;
contentref: RefObject<HTMLTextAreaElement>;
tagsref: RefObject<HTMLInputElement>;
finish: () => void;
reset: () => void;
main: CounterState;
id: String | string[] | undefined;
}) => {
return (
<div>
{main.data.map((res: da, index: number) => {
if (res.idx == id) {
return (
<div key={index}>
<div className="section">
<h1 className="title">
<input
className="titleinput"
ref={titleref}
placeholder="약속이름 작성"
/>
</h1>
<div className="time">
<div className="timetitle">약속 시간</div>
<div className="timecontent">
<p>Date:</p>
<input ref={dateref} className="timedateinput" />
<p>Time:</p>
<input ref={timeref} className="timetimeinput" />
</div>
</div>
<div className="mapinfo">
<div className="map">
<iframe
width="350"
height="350"
loading="lazy"
></iframe>
</div>
<div className="mapdes">
지도에
<h3>
<input
ref={addressref}
className="mapdesinput"
placeholder="주소 또는 장소 이름 작성"
/>
</h3>
검색해주세요
</div>
</div>
<div className="content">
<h3 className="contitle">계획</h3>
<div className="condes">
<textarea
ref={contentref}
className="condesinput"
placeholder="세부내용 작성"
/>
</div>
</div>
<input
ref={tagsref}
className="tagsinput"
placeholder="#으로 태그를 구분해주세요"
/>
<div className="tags">
<div className="tag">예시</div>
<div className="tag">예시</div>
<div className="tag">예시</div>
</div>
<div className="buttons">
<div className="reset">
<button onClick={reset}>초기화</button>
</div>
<div className="finish">
<button onClick={finish}>완료</button>
</div>
</div>
</div>
<style jsx>
{`
.section {
display: flex;
align-items: center;
flex-direction: column;
min-height: 900px;
background-color: #f5b467;
width: 100%;
}
.section > .title {
margin: 1%;
color: #196aff;
}
.section > .title > .titleinput {
font-size: 28px;
text-align: center;
font-weight: bolder;
width: 350px;
}
.scetion > .time {
width: 100%;
}
.section > .time > .timetitle {
font-size: 28px;
font-weight: bolder;
width: 350px;
text-align: center;
margin: 2%;
display: flex;
flex-direction: column;
}
.section > .time > .timetitle::after {
content: " ";
border: 1px solid #636beb;
width: 90%;
margin: auto;
}
.section > .time > .timecontent {
font-size: 28px;
font-weight: bolder;
width: 350px;
text-align: center;
display: flex;
justify-content: space-around;
}
.section > .time > .timecontent > * {
font-size: 18px;
font-weight: bolder;
max-width: 30%;
}
.section > .time > .timecontent > .timetimeinput {
font-size: 18px;
font-weight: bolder;
max-width: 30%;
}
.section > .time > .timecontent > .timtdateinput {
font-size: 18px;
font-weight: bolder;
max-width: 40%;
}
.section > .mapinfo {
border: 5px solid #636beb;
border-radius: 10px;
max-width: 354px;
margin: 1%;
}
.section > .mapinfo > .map {
background-color: whitesmoke;
}
.section > .mapinfo > .mapdes {
font-size: 20px;
text-align: center;
padding: 1%;
background-color: whitesmoke;
}
.section > .mapinfo > .mapdes > h3 > .mapdesinput {
font-size: 20px;
text-align: center;
font-weight: bolder;
}
.section > .content {
min-width: 350px;
display: flex;
flex-direction: column;
margin: 1%;
border: 3px solid #636beb;
background-color: #eab7f5;
}
.section > .content > .contitle {
text-align: center;
color: #196aff;
font-size: 28px;
width: 100%;
display: flex;
flex-direction: column;
}
.section > .content > .contitle::after {
content: " ";
border: 1px solid #636beb;
width: 80%;
margin: auto;
}
.section > .content > .condes {
text-align: center;
font-weight: bolder;
font-size: 18px;
width: 100%;
}
.section > .content > .condes > .condesinput {
text-align: center;
font-weight: bolder;
font-size: 18px;
margin: 1%;
width: 80%;
height: 100px;
}
.tagsinput {
width: 350px;
font-size: 18px;
}
.section > .tags {
width: 350px;
display: flex;
flex-flow: wrap;
justify-content: center;
}
.section > .tags > .tag {
border: 1px solid #636beb;
border-radius: 16px;
margin: 1%;
padding: 1%;
background-color: #636beb;
font-weight: bolder;
color: whitesmoke;
}
.section > .tags > .tag::before {
content: "#";
}
.section > .buttons {
display: flex;
justify-content: center;
width: 90%;
max-width: 350px;
}
.section > .buttons > * {
width: 200px;
}
.section > .buttons > * > * {
font-weight: bolder;
font-size: 28px;
margin: 5%;
max-width: 100%;
padding: 5%;
border-radius: 12px;
}
.section > .buttons > .finish {
display: flex;
justify-content: end;
}
.section > .buttons > .reset > * {
background-color: yellow;
border: 1px solid;
}
.section > .buttons > .finish > * {
background-color: #6856f8;
border: 1px solid;
display: flex;
justify-content: end;
}
`}
</style>
</div>
);
}
})}
</div>
);
};
export default Modify;
container
import { useRouter } from "next/router";
import { useEffect, useRef, useState } from "react";
import { useDispatch } from "react-redux";
import { useSelector } from "react-redux";
import Modify from "../../../../components/form/firstform/update/[id]";
import { dataupdate } from "../../../../store/actions/action";
import { CounterState, RootState } from "../../../../store/types/state";
import { da } from "../../../../type";
const ModifyContainer = () => {
const dispatch = useDispatch();
const { main }: { main: CounterState } = useSelector(
(state: RootState) => state
);
const { query } = useRouter();
const id: String | string[] | undefined = query.id;
useEffect(() => {
main.data.find((res) => {
if (res.idx == id) {
titleref.current!.value = res.text.title;
dateref.current!.value = res.text.date;
timeref.current!.value = res.text.time;
addressref.current!.value = res.text.address;
contentref.current!.value = res.text.content;
tagsref.current!.value = "#" + res.text.tags?.join("#");
return res;
}
});
}, [main.data, id]);
const titleref = useRef<HTMLInputElement>(null);
const dateref = useRef<HTMLInputElement>(null);
const timeref = useRef<HTMLInputElement>(null);
const addressref = useRef<HTMLInputElement>(null);
const contentref = useRef<HTMLTextAreaElement>(null);
const tagsref = useRef<HTMLInputElement>(null);
const reset: () => void = () => {
main.data.find((res) => {
if (res.idx == id) {
titleref.current!.value = res.text.title;
dateref.current!.value = res.text.date;
timeref.current!.value = res.text.time;
addressref.current!.value = res.text.address;
contentref.current!.value = res.text.content;
tagsref.current!.value = "#" + res.text.tags?.join("#");
return res;
}
});
};
const finish: () => void = () => {
const data: da | undefined = makedata();
if (data != undefined) {
dispatch(dataupdate(data));
if (main.common.login == "admin") {
alert(`id를 기억하세요 id:${id}`);
}
} else {
alert("태그 제외 모든 빈칸을 넣어주세요");
}
};
const makedata = () => {
if (
titleref.current?.value &&
dateref.current?.value &&
timeref.current?.value &&
addressref.current?.value &&
contentref.current?.value
) {
const tagarr: string[] | undefined = tagsref.current?.value.split("#");
tagarr?.splice(0, 1);
const data: da = {
idx: query.id!.toString(),
currentform: "first",
maker: main.common.login,
text: {
address: addressref.current?.value,
content: contentref.current?.value,
date: dateref.current?.value,
tags: tagarr ? tagarr : [],
time: timeref.current?.value,
title: titleref.current?.value,
},
};
return data;
}
};
return (
<div>
<Modify
main={main}
titleref={titleref}
dateref={dateref}
timeref={timeref}
addressref={addressref}
contentref={contentref}
tagsref={tagsref}
finish={finish}
reset={reset}
id={id}
/>
</div>
);
};
export default ModifyContainer;
container 기준으로 설명을 하도록 해보겠습니다.
우선 uesEffect 부분 보면
useEffect(() => {
main.data.find((res) => {
if (res.idx == id) {
titleref.current!.value = res.text.title;
dateref.current!.value = res.text.date;
timeref.current!.value = res.text.time;
addressref.current!.value = res.text.address;
contentref.current!.value = res.text.content;
tagsref.current!.value = "#" + res.text.tags?.join("#");
return res;
}
});
}, [main.data, id]);
여기서 랜더링 되기전에 기본 값을 넣어줘야 되기때문에 useref로 특정 html요소 정해주고 해당 요소의 value를 설정해주었습니다.
tagarr은 join으로 중간에 #넣어주고 젤처음에는 따로#을 넣어주었습니다.
const reset: () => void = () => {
main.data.find((res) => {
if (res.idx == id) {
titleref.current!.value = res.text.title;
dateref.current!.value = res.text.date;
timeref.current!.value = res.text.time;
addressref.current!.value = res.text.address;
contentref.current!.value = res.text.content;
tagsref.current!.value = "#" + res.text.tags?.join("#");
return res;
}
});
};
reset부분은 누르면 useeffect부분이랑 똑같은 기능을 실행하여 최초 상태로 만들어주게 됩니다.
const makedata = () => {
if (
titleref.current?.value &&
dateref.current?.value &&
timeref.current?.value &&
addressref.current?.value &&
contentref.current?.value
) {
const tagarr: string[] | undefined = tagsref.current?.value.split("#");
tagarr?.splice(0, 1);
const data: da = {
idx: query.id!.toString(),
currentform: "first",
maker: main.common.login,
text: {
address: addressref.current?.value,
content: contentref.current?.value,
date: dateref.current?.value,
tags: tagarr ? tagarr : [],
time: timeref.current?.value,
title: titleref.current?.value,
},
};
return data;
}
};
makedata는 입력된 데이터를 활용하여 da양식의 객체를 만들어주는 함수 입니다. route에서 해당 id를 받아와서 !로 notnull이라고 해주고 tostring으로 배열의 가능성을 없애줍니다.
그리고 tagarr은 없는경우 빈배열을 넣어주도록 세팅했습니다.
const finish: () => void = () => {
const data: da | undefined = makedata();
if (data != undefined) {
dispatch(dataupdate(data));
if (main.common.login == "admin") {
alert(`id를 기억하세요 id:${id}`);
}
} else {
alert("태그 제외 모든 빈칸을 넣어주세요");
}
};
finsih함수는 makedata로 만들어진 데이터를 가져와서 dispatch로 redux함수를 실행하고 data데이터가 undefined이면 빈칸없이 입력하라고 알림창을 뛰워주게 됩니다.
const titleref = useRef<HTMLInputElement>(null);
const dateref = useRef<HTMLInputElement>(null);
const timeref = useRef<HTMLInputElement>(null);
const addressref = useRef<HTMLInputElement>(null);
const contentref = useRef<HTMLTextAreaElement>(null);
const tagsref = useRef<HTMLInputElement>(null);
여기서 usestate말고 useRef쓴 이유가 궁금할수 있는데 검색해보니까 usestate는 값이변화할때마다 rerendering된다고 봤습니다. useref는 그 값만 변한다고 봐서 useref가 더 효율적이라고 생각했습니다.
그리고 제가 ***.**?.* 이런거 썼는데 이건 !를 붙이면 해당 요소가 null이 아니다 라는 뜻이고 ?는 null일수도 잇고 아닐수도 있다는 뜻입니다. makedata부분에 ?썼는데 !가 더 맞는 코드 같아요 ㅎㅎ 저대로 작성해놓은 이유는 저렇게하면 어떤오류가 날까 궁금해서 해봤는데 오류가 안나오네요 ㅎㅎ
'next+ts' 카테고리의 다른 글
next+ts 폼선택 페이지 전체 코드 둘러보기(Component+container) (0) | 2022.05.04 |
---|---|
next+ts 폼관련 페이지 전체 코드 둘러보기(Component+container) (0) | 2022.05.03 |
next+ts18일차 link연결 +redux에서 route사용 (0) | 2022.04.30 |
next+ts17일차 update 페이지 (0) | 2022.04.29 |
next+ts 16일차 login saga비동기 처리 (0) | 2022.04.28 |