React 留言板實作


Posted by chihyu on 2021-01-25

留言板

建立檔案基本結構

  1. 在 src 資料夾裡面建立一個 components 資料夾
  2. 在 components 資料夾裡面建立一個專案資料夾 ex. App
  3. App 資料夾裡面的檔案:App.js、App.test.js、index.js
  4. 在 index.js 把 App.js export 出去
    // 就寫這兩行
    import App from "./App";
    export default App;
    
  5. 在 src 資料夾裡面的 index.js 引入 App.js 並 render 出來
    import React from "react";
    import ReactDOM from "react-dom";
    import App from "./components/App";
    // ReactDOM.render(<App />, document.getElementById("root"));
    ReactDOM.render(<App />, document.getElementById("root"));
    

切版

  1. 引入 styled-component
    import styled from "styled-components";
    
  2. 在 function App() 把留言板主要架構的 component 寫入
  3. 幫 component 加上 style
  4. 把留言內容寫一個 function component,把會變動的內容用參數帶入
    function Message({ author, time, children }) {
    return () 
    }
    

串接資料

  1. 宣告留言的 state
    // 先引入
    import React, { useState } from "react";
    
    // 在 function App 裡面宣告
    const [messages, setMessages] = useState([])
    
  2. 使用 useEffect (因為是要在 render 完拿資料)
    // 先引入
    import React, { useState, useEffect } from "react";
    
    // 在 function App 裡面使用,因為只要執行一次,所以後面傳空陣列因
    useEffect(() => {
    }, [])
    
  3. 在 useEffect 裡面串接 api
    useEffect(() => {
     fetch(API_ENDPOINT) // api 
       .then((res) => res.json()) 
       .then((data) => {
         setMessages(data) // setter 將資料帶入
       })
       .catch(err => { // 錯誤處理
         setApiError(err.message)
       })
    }, [])
    
  4. 把資料帶入留言板
    <MessageList>
    {messages.map(message => (
     <Message key={message.id} author={message.nickname} time={message.createdAt}>
       {message.body}
     </Message>
    ))}
    </MessageList>
    
  5. 做錯誤處理
    api 錯誤,沒找到資料時:
    // 使用 useState
    const [messageApiError, setMessageApiError] = useState(null);
    {messageApiError && (
    <ErrorMessage>
     Something went wrong.{messageApiError.toString()}
    </ErrorMessage>
    )}
    
    沒有留言時:
    {messages.length === 0 && <div>No Message</div>}
    
  6. 使用 propTypes 檢查 prop 的型態是不是正確的
    // 引入
    import PropTypes from 'prop-types';
    
    // 把參數帶入 propTypes
    Message.propTypes = {
    author: PropTypes.string,
    time: PropTypes.string,
    children: PropTypes.node
    }
    

實作功能

  1. 實作 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)
    }
    
  2. 實作送出表單功能
    // 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)
     })
    }
    
  3. 送出空白留言的錯誤處理
    // 使用 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);
    }
    
  4. 預防一直點擊按鈕,確認是不是在送出留言的 state
    // 使用 useState
    const [isLoadingPostMessage, setIsLoadingPostMessage] = useState(false);
    // 如果是 true 就不管他,不然就在發 api 之前設成 true
    if (isLoadingPostMessage) {
     return;
    }
    setIsLoadingPostMessage(true);
    // 在結果回來之後設成 false
    setIsLoadingPostMessage(false)
    
  5. 在 page 裡面設置 Loading 狀態
    // 如果正在 Loading 就顯示 Loading
    {isLoadingPostMessage && <Loading>Loading...</Loading>}
    

#Web #React #message-board







Related Posts

CSS保健室|width、height

CSS保健室|width、height

npm套件教學

npm套件教學

七天打造自己的 Google Map 應用入門 - Day04

七天打造自己的 Google Map 應用入門 - Day04


Comments