- 宣告留言的 state
// 先引入
import React, { useState } from "react";
// 在 function App 裡面宣告
const [messages, setMessages] = useState([])
- 使用 useEffect (因為是要在 render 完拿資料)
// 先引入
import React, { useState, useEffect } from "react";
// 在 function App 裡面使用,因為只要執行一次,所以後面傳空陣列因
useEffect(() => {
}, [])
- 在 useEffect 裡面串接 api
useEffect(() => {
fetch(API_ENDPOINT) // api
.then((res) => res.json())
.then((data) => {
setMessages(data) // setter 將資料帶入
})
.catch(err => { // 錯誤處理
setApiError(err.message)
})
}, [])
- 把資料帶入留言板
<MessageList>
{messages.map(message => (
<Message key={message.id} author={message.nickname} time={message.createdAt}>
{message.body}
</Message>
))}
</MessageList>
- 做錯誤處理
api 錯誤,沒找到資料時:// 使用 useState
const [messageApiError, setMessageApiError] = useState(null);
{messageApiError && (
<ErrorMessage>
Something went wrong.{messageApiError.toString()}
</ErrorMessage>
)}
沒有留言時:{messages.length === 0 && <div>No Message</div>}
- 使用 propTypes 檢查 prop 的型態是不是正確的
// 引入
import PropTypes from 'prop-types';
// 把參數帶入 propTypes
Message.propTypes = {
author: PropTypes.string,
time: PropTypes.string,
children: PropTypes.node
}
- 實作 textarea 的功能,做成 control component,用 useState
// textarea 的 value 使用 useState
const [value, setValue] = useState();
// value 的參數帶 value,onChange 的參數帶一個 function
<MessageTextArea value={value} onChange={handleTextareaChange} rows={5} />
// function 裡面設置 setValue (setter)
const handleTextareaChange = e => {
setValue(e.target.value)
}
- 實作送出表單功能
// onSubmit 的參數帶一個 function
<MessageForm onSubmit={handleFormSubmit}>
// function 裡面先實作 submit 功能,用 post 把資料送出
const handleFormSubmit = e => {
e.preventDefault(); // 先防止預設事件
fetch('https://student-json-api.lidemy.me/comments', {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
nickname: 'sun',
body: value
})
})
.then(res => res.json())
.then(data => {
fetchMessages() // submit 後再 call api,取得最新資料
})
}
// 因為重複使用到 call api,要把 call api 的部分另外宣告出來
const fetchMessages = () => {
return fetch(API_ENDPOINT)
.then((res) => res.json())
.then((data) => {
setMessages(data)
})
.catch(err => {
setApiError(err.message)
})
}
- 送出空白留言的錯誤處理
// 使用 useState
const [postMessageError, setPostMessageError] = useState();
// 如果回傳的資料不 ok 就回傳 api 的訊息
if (data.ok === 0) {
setPostMessageError(data.message)
return;
}
// 寫在 submit 下面,把回傳的訊息帶入
<SubmitButton>送出留言</SubmitButton>
{postMessageError && <ErrorMessage>{postMessageError}</ErrorMessage>}
如果點回 textarea 錯誤處理的訊息就消失// 在 textarea 加上
onFocus={handleTextareaFocus}
// 當 textarea 被點擊就把錯誤處理改成 null
const handleTextareaFocus = e => {
setPostMessageError(null);
}
- 預防一直點擊按鈕,確認是不是在送出留言的 state
// 使用 useState
const [isLoadingPostMessage, setIsLoadingPostMessage] = useState(false);
// 如果是 true 就不管他,不然就在發 api 之前設成 true
if (isLoadingPostMessage) {
return;
}
setIsLoadingPostMessage(true);
// 在結果回來之後設成 false
setIsLoadingPostMessage(false)
- 在 page 裡面設置 Loading 狀態
// 如果正在 Loading 就顯示 Loading
{isLoadingPostMessage && <Loading>Loading...</Loading>}