참고 내용
아직 DB를 사용하지 않아서
임시 테스트 데이터를 사용하고 있다.
const tempTc = [
{ sortId: "0", tc: "零", jyutJam: "ling4 lin4", title: "숫자 0" },
... ,
{ sortId: "10", tc: "十", jyutJam: "sap6", title: "숫자 10" }];
const tempWord = [
{ sortId: "0", tc: "你好", jyutJam: "nei5 hou2", title: "안녕하세요" },
... ,
{ sortId: "10", tc: "再見", jyutJam: "zoi3 gin3", title: "또 만나요" },
];
현재 한자 카드의 링크는
<Link href={`/cantonese/${data.sortId}`}>...</Link>
한자 사전 페이지
동적 라우팅 page.js 파일
[Dynamic Routes 편]
[Next.js 정식 설명]
전에 이미 만들었지만 다시 설명.
.\app\cantonese\\[id]\page.js
를 만들었다.
/cantonese
는 리스트 페이지이고/cantonese/id
는 상세 페이지이다.
현재 cantonese 폴더 내용 :
app
└ cantonese
└ word
| └ page.js
└ [id]
| └ page.js
└ page.js
동적 라우팅은 대괄호으로 사용한다.
대괄호 안의 내용을 변수로 받고,
페이지 UI는 폴더 안의 page.js를 보여준다.
Dictionary 컴포넌트 기본틀
// ..src\app\cantonese\[id]\page.js
export default function Dictionary(props) {
return <> {props.params.id} </>;
}
기본틀도 이전에 만들었다.
이제 사전에서 보여줄 데이터를 정리하자...
현재는소팅
, 한자
, 발음
, 타이틀
이 있다.
추가로 설명
과 분류
가 필요하다.
설명의 경우, 발음에 따라서 뜻이 다르고
같은 발음도 여러 뜻이 있을 수 있다.
{
sortId: "0",
tc: "零",
jyutJam: "ling4 lin4",
title: "숫자 0",
category: "숫자",
mean: {
ling4: ["숫자 0", "떨어지다", "적은 수량"]
lin4: ["부족 이름"]
}
}
데이터 읽기
문제는 여기다.
- 어떻게 여기서 데이터를 사용하나?
- 현재 페이지의 데이터를 어떻게 찾을 것인가?
이전 페이지에서 이미getCardData
를 사용해서
모든 데이터를 읽었다.
하지만 지금 다른 페이지로
해당 데이터를 가지고 있지 않다.
생각나는 방법은
- 다시 데이터를 읽는다
- 데이터를 부모에서 전달한다
2번의 방법은
- local storage 혹 session을 사용
- 주소에 쿼리의 형태로 데이터를 입력
문제는 1번의 경우...
반드시 이전 페이지에서 들어와야 한다.
2번의 경우 url이 너무 길어지고
해당 내용과 관련이 없어질 수 있다.
(애초 sortId를 사용해서 관련성은 없지만)
결국은...
임시 데이터이기 때문에
다시 읽는 방식을 택했다.
하지만 실제로 사용할 때는 서버 비용의 물 먹는 하마가 될 수 있을 것 같다.
데이터 매치
지금 tempTc
임시 데이터는 배열이다.
배열에서 같은 sortId
를 찾는 방법을 사용할 수 있다.
find()
함수를 사용해봤다.
const data = tempTc.find((tc) => tc.sortId == props.params.id);
반복문이어서
요소를 찾을 때까지 반복한다.
...부하가되는 작업은 아니다.
애초 변수도 tempTc
하나을 읽는 것이다.
단 찾는 번호가 마지막이면..
처음부터 마지막까지 반복으로 비교를 한다.
그래서 생각한 방법으로tc
(한자)를 주소로 사용하고tempTc
를 객체로 만들어서tc
를 key로 사용하는 방법을 생각했다.
추가로
데이터를 별도의 파일로 만들었다.
Json파일으로 만드는 것이 더 적합할 수 있지만..
우선 js파일로 만들었다.
// .\public\data.js
export const tempTc = {
"零" : {
sortId: "0",
tc: "零",
jyutJam: "ling4 lin4",
title: "숫자 0",
category: "숫자",
mean: {
ling4: ["숫자 0", "떨어지다", "적은 수량"]
lin4: ["부족 이름"]
}
},
...
}
데이터 매치는 많이 간단해진다.
const data = tempTc[props.params.id];
tempTc
전체를 사용하는 것은 차이가 없다.
그저... json으로 받는 다고 가정하면
해당 데이터만 반환하기 때문에 조금(?아주 조금) 효율적이지 않을 까 싶었다.
데이터를 변경했기 때문에
해당 링크를 사용하는 페이지도 변경해야 한다.
// .\app\component\CnCard.js - Link 부분
<Link href={`/cantonese/${data.tc}`}>...</Link>
페이지 코드
// ..src\app\cantonese\[id]\page.js
import { tempTc } from "./data";
export default function Dictionary(props) {
const data = tempTc[props.params.id];
if (data == undefined || data == null ) {
return <>{props.params.id}의 데이터가 없습니다.</>
}
const jyutJamArr = data.jyutJam?.split(" ");
let meanCount = 0;
return (
<>
<h1>{data.tc}</h1>
<p>월음 : {data.jyutJam}</p>
<p>분류 : {data.category}</p>
<p>뜻</p>
{jyutJamArr.map((jyutJam)=> {
return (
<p key={"jyut-", jyutJam}>{jyutJam}</p>
{data.mean[jyutJam].map((mean) => {
meanCount++;
return <p key={meanCount}>{mean}</p>
})}
)
})}
</>
);
}
데이터를 매치한다
const data = tempTc[props.params.id];
매치된 데이터가 없으면 오류 문자를 출력한다.
if (data == undefined || data == null) {
return <>{props.params.id}의 데이터가 없습니다.</>;
}
월음을 분리한다
const jyutJamArr = data.jyutJam?.split(" ");
임시 뜻 번호 변수를 선언한다.
let meanCount = 0;
순서대로 데이터를 출력한다
return (
<>
<h1>{data.tc}</h1>
<p>월음 : {data.jyutJam}</p>
<p>분류 : {data.category}</p>
...
</>
);
풀이 부분은 월음을 반복해서 월음을 표기한다
<p>뜻</p>;
{
jyutJamArr.map((jyutJam) => {
return (
<p key={("jyut-", jyutJam)}>{jyutJam}</p>
...
)
});
}
data에서 같은 월음을 찾아서 반복한다.
반복할 때 meanCount
을 추가해서 key값으로 전달한다.
반복한 요소(뜻)을 출력한다.
( jyutJam
은 이전 반복문의 요소이다 )
{
data.mean[jyutJam].map((mean) => {
meanCount++;
return <p key={meanCount}>{mean}</p>;
});
}
단어
단어와 한자는
key값이 다르기 때문에
같은 페이지를 사용할 수 있을 것 같다.
데이터 매치를 할 때,
한자와 단어 데이터로 매치해야 한다.
const data = tempTc[props.params.id] ?? tempWord[props.params.id];
단어의 경우 한자와 다르게
발음을 분리할 필요가 없다.
그래서 밑 "뜻" 부분을Dictionary
컴포넌트 안에TcContent
컴포넌트와WordContent
컴포넌트를 만들었다
function TcContent(){
return
{ jyutJamArr.map((jyutJam)=> {
return (
<p key={"jyut-", jyutJam}>{jyutJam}</p>
{ data.mean[jyutJam].map((mean) => {
meanCount++;
return <p key={meanCount}>{mean}</p>
})}
)
})}
}
function WordContent(){
{data.mean[jyutJam].map((mean) => {
meanCount++;
return <p key={meanCount}>{mean}</p>
})}
}
한자 vs 단어 구분 변수도 추가했다.
const isTc = tempTc[props.params.id] != null;
결과
// ..src\app\cantonese\[id]\page.js
import { tempTc } from "./data";
export default function Dictionary(props) {
const id = props.params.id;
const data = tempTc[id] ?? tempWord[id];
if (data == undefined || data == null ) {
return <>{props.params.id} 데이터 없음</>
}
let meanCount = 0;
return (
<>
<h1>{data.tc}</h1>
<p>월음 : {data.jyutJam}</p>
<p>분류 : {data.category}</p>
<p>뜻</p>
{ isTc ? <TcContent/> : <WordContent/> }
</>
);
function TcContent(){
const jyutJamArr = data.jyutJam?.split(" ");
return
{ jyutJamArr.map((jyutJam)=> {
return (
<p key={"jyut-", jyutJam}>{jyutJam}</p>
{ data.mean[jyutJam].map((mean) => {
meanCount++;
return <p key={meanCount}>{mean}</p>
})}
)
})}
}
function WordContent(){
{data.mean[jyutJam].map((mean) => {
meanCount++;
return <p key={meanCount}>{mean}</p>
})}
}
}
결과적으로는
원하는 데이터가 출력된다.
하지만 데이터 사용 효율은
데이터 베이스를 선택할 때,
더 많은 고민을 해야할 것 같다.