実現したいこと
- JSONからTypeScriptにデータを読み込んで表示させたい
前提
Next.js/React TypeScript JSONを使ってWebサイトを作っています。
JSONからデータを読み込もうとした際に以下のエラーメッセージが発生しました。
発生している問題・エラーメッセージ
TypeError: Cannot read properties of undefined (reading 'h1')
該当のソースコード
TypeScript
1import styles from 'styles/keyword.module.css'; 2 3export function Keyword(props) { 4 5 const keyword = props.keyword; 6 7 return ( 8 <div className={styles.sideBySide}> 9 <h1>{keyword.h1}</h1> 10 {keyword.p.map((p, index) => ( 11 <p key={index} className={`${styles.icon} ${styles.iconText}`}> 12 {p} 13 </p> 14 ))} 15 </div> 16 ); 17} 18 19// Fetching data from the JSON file 20// import path from 'path' 21 22export async function getStaticProps() { 23 const filePath = path.join(process.cwd(), 'data.json'); 24 const res = await fetch(filePath); 25 const objectData = await res.json(); 26 27 return { 28 props: objectData.data 29 }; 30 31}
JSON
1{ 2 "data": { 3 "keyword": { 4 "h1": "be used to", 5 "p": [ 6 "助動詞", 7 "熟語" 8 ] 9 }, 10 "tips": [ 11 "発音に注意", 12 "be used to / get used to の違いに注意", 13 "used to 原形 / be used to -ing / be used to 原形 の違いに注意" 14 ], 15 "japanese": { 16 "be used to 名詞で「名詞に慣れている」" 17 }, 18 "english": { 19 "quote": "to have experienced something so that it no longer seems surprising, difficult, strange etc", 20 "source": "ロングマン現代英英辞典" 21 } 22 } 23}
試したこと
いろいろと調べたところ、JSONからデータをfetchするときに遅延が起きていてkeywordコンポーネントにデータが渡せていないんじゃないかというところまで現在仮説を立てました。
そして、遅延を回避するため、次のようなコードに修正しました。
TypeScript
1import { useEffect, useState } from 'react'; 2import styles from 'styles/keyword.module.css'; 3 4export function Keyword(props) { 5 const [keyword, setKeyword] = useState(null); 6 7 useEffect(() => { 8 async function fetchData() { 9 const response = await fetch('/data.json'); 10 const data = await response.json(); 11 setKeyword(data.data.keyword); 12 } 13 fetchData(); 14 }, []); 15 16 if (!keyword) { 17 return <div>Loading...</div>; 18 } 19 20 return ( 21 <div className={styles.sideBySide}> 22 <h1>{keyword.h1}</h1> 23 {keyword.p.map((p, index) => ( 24 <p key={index} className={`${styles.icon} ${styles.iconText}`}> 25 {p} 26 </p> 27 ))} 28 </div> 29 ); 30}
しかし、結果としては
TypeScript
1 if (!keyword) { 2 return <div>Loading...</div>; 3 }
の部分の「Loading...」が表示されるだけで、本来表示したい
TypeScript
1 <div className={styles.sideBySide}> 2 <h1>{keyword.h1}</h1> 3 {keyword.p.map((p, index) => ( 4 <p key={index} className={`${styles.icon} ${styles.iconText}`}> 5 {p} 6 </p> 7 ))} 8 </div>
は表示されない状況です。
補足情報(FW/ツールのバージョンなど)
{ "name": "nextdictionary", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "@emotion/react": "^11.10.5", "@emotion/styled": "^11.10.5", "@mui/icons-material": "^5.11.0", "@mui/material": "^5.11.8", "@next/font": "13.1.6", "@types/node": "18.11.18", "@types/react": "18.0.27", "@types/react-dom": "18.0.10", "eslint": "8.33.0", "eslint-config-next": "13.1.6", "next": "^13.1.7-canary.26", "react": "18.2.0", "react-dom": "18.2.0", "react-icons": "^4.7.1", "typescript": "4.9.5" } }
プログラミング初心者・はじめてのteratail利用ということで
至らない点があるかと思いますが
どうぞよろしくお願いいたします。
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。