各位大大您好!最近遇到一個棘手的問題想向各位請教~
當我進去某個指定人物的頁面後,會利用useEffect來執行第一次的render,從資料庫抓取該角色的詳細資料,並將其存入到useState的array中,並將其資料render至該頁面中,但遇到了一個問題,進去頁面時會質性第一次render,在執行useEffect(也就是抓取該人物的詳細資料),但第一次render時,還未抓取到該人物的資料,造成undefined,想請問該怎麼辦QQ
ChampionDetails.js :
const ChampionsDetail = () => {
const location = useLocation();
const history = useHistory();
const { name, id } = useParams(); // name:Iron man ; id:1
const [champDetails, setChampDetails] = useState({ clothes: {}, skills: {}});
const championInfo = location.state;
/* 畫面初始值 */
useEffect(() => {
fetchChampionDetail();
document.title = `${name}'s Detail`;
},[]);
/* function fetchDetail 抓取該人物的詳細資料 */
const fetchChampionDetail = async () => {
const result = await Axios.get(
`http://localhost:3001/champions_detail/id=${id}&${name}`
);
Axios.all([result])
.then(
Axios.spread((result) => {
setChampDetails({
clothes: result.data[0],
skills: result.data[1]
});
})
)
.catch((errors) => {
console.error(errors);
});
};
/* function handleBackClick */
const handleBackClick = () => {
history.goBack();
};
return (
<div>
<h1>
Champion {name}'s Detail Pages
</h1>
<button
onClick={() => {
handleBackClick();
}}
>Back to the Champion Page</button>
<p>{champDetials.clothes[0].clothes_name}</p>
</div>
);
}
export default ChampionsDetail;
{champDetials.clothes[0].clothes_name}
在這裡出錯了
先謝謝各位的幫忙!!,仍在學習中,任何指教都願意聆聽~
const ChampionsDetail = () => {
const location = useLocation();
const history = useHistory();
const { name, id } = useParams();
// 在獲得後端資料前,先將state值設定為一個可以讓你辨識「還沒獲得後端資料」的值
const [champDetails, setChampDetails] = useState(undefined);
const championInfo = location.state;
useEffect(() => {
fetchChampionDetail();
document.title = `${name}'s Detail`;
},[]);
const fetchChampionDetail = async () => {
const result = await Axios.get(
`http://localhost:3001/champions_detail/id=${id}&${name}`
);
Axios.all([result])
.then(
Axios.spread((result) => {
setChampDetails({
clothes: result.data[0],
skills: result.data[1]
});
})
)
.catch((errors) => {
console.error(errors);
});
};
const handleBackClick = () => {
history.goBack();
};
/*
在JS中,「 A && B 」 代表的是當A為true,則回傳B
下面<p></p>中的JS寫法你也可以寫成:
if(champDetials !== undefined)
return champDetials.clothes[0].clothes_name;
*/
return (
<div>
<h1>
Champion {name}'s Detail Pages
</h1>
<button
onClick={() => {
handleBackClick();
}}
>Back to the Champion Page</button>
<p>{champDetials && champDetials.clothes[0].clothes_name}</p>
</div>
);
}
export default ChampionsDetail;
喔喔!!所以useState是可以先定義為 undefined!!,我在提問前查了網路上很多資料,有些是說可以再用一個useEffect去來看是否更新值,不知道有沒有這種寫法QAQ 另外您的方法,成功讓我render成功了!!!我等等再run一次您跟我說的概念~~謝謝您!
對了,你detail拼錯了XD
因為不只有一個值要render,所以如果要的話 是全部都要用您說的A && B
才能在整個頁面使用嗎QAQ
有我看到了哈哈 我剛剛測試發現了~~嘿嘿
看你的資料是不是從後端拿的啊~ 一般而言,我們會把需要同一份資料的頁面拆出來成一個component,這樣你只要寫一次下面的code就能解決所有問題囉
資料 && <頁面元件 />
那這樣像您說的 我把它拆成Detail.js 我要把render的畫面放進去是嗎? 不然我不太懂您說的這個方法QQ
類似這樣的概念
return (
<div>
<h1>
Champion {name}'s Detail Pages
</h1>
<button
onClick={() => {
handleBackClick();
}}
>Back to the Champion Page</button>
{champDetails && <Detail data={champDetails}>}
</div>
);
}
另外有一種狀況是當你需要call多次api向後端拿不同資料才能呈現單一頁面,這時會比較複雜,我所知道的有兩種做法:
Promise.all()
等每隻api都傳回來再初始化,但這個比較複雜也比較容易出錯那像這樣呢
ChampionDetail.js
return (
<div className="detailContainer">
{champDetails && <Detail data={champDetails}>}
</div>
);
}
Detail.js: (ChampionDetails.js會傳送一個props(champDetails)過來)
const Detail = ({champDetails}) => {
return (
<div>
<h1>{champDetails.clothes[0].clothes_name}</h1>
<p>{champDetails.skills[0].skill_name}</p>
</div>
)
}
這樣對嗎~~?
理論上是對的,就看執行結果符不符合你的期望
Andy Chang
下面那個方法,未來我會試做看看!! 另外題外話,想問有方法將資料的資料做成API嗎XD 現在剛接觸這個領域中~抱歉問題很多
好了解了 我試做看看!!! 總之謝謝您!!!
將資料的資料做成API
不懂, 你可能要再描述清楚一點
應該說如何做屬於自己網頁的API,畢竟我的資料現在只存在我的MYSQL中,未來若有相關網頁需要,就可以直接抓API了,而不是像現在去跟資料庫撈哈哈
Andy Chang了解了 感謝您的解釋~~非常有幫助,Firebase我有聽過,未來我會研究看看的 謝謝~