iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
Modern Web

30天React練功坊-攻克常見實務/面試問題系列 第 28

30天React練功坊-攻克常見實務/面試問題 Day28: Fetch all synonyms for given word(interview question)

  • 分享至 

  • xImage
  •  
tags: ItIron2023 react

前言

昨天我們完成了add emoji onclick的問題,額外用了幾個state以及timer去達到題目的要求,今天我們來看另一個有趣的情境面試題吧!

本日題目

請觀察這個codesandbox以及下方的instructions。

題目目標

建立一個React應用程式,讓用戶輸入一個單詞,然後獲取並顯示該單詞的同義詞。當用戶點擊一個同義詞時,輸入和顯示的列表應更新為新單詞。
以下為一些注意事項
1. 請閱讀這份文件並找出對應的api自行使用
2. 讀取時與找不到同義字時應有對應的文字提示
3. 請勿使用其他第三方的套件

最終期待呈現的結果如下圖。

day28-demo-gif

請以下方的starter code開始

import React, { useState } from "react";

const App = () => {
  const [word, setWord] = useState("");
  // TODO: Declare your state variables for holding synonyms and loading state

  const handleSubmit = (e) => {
    e.preventDefault();
    // TODO: Implement fetching synonyms
  };

  return (
    <div className="App">
      <h1>Fetch all synonyms for a given word</h1>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={word}
          onChange={(e) => setWord(e.target.value)}
          placeholder="Enter a word"
        />
        <button type="submit">Find Synonyms</button>
      </form>
      {/* TODO: Display loading state or fetched synonyms */}
    </div>
  );
};

export default App;

解答與基本解釋

這類的題目也是常見的面試問題,開頭會先提供你詳細的指示與需要的api文件,starter code的部分也僅是給你最基本的架構,而你需要在限定時間內用自己的一套辦法完成所有的需求,今天的題目也並不困難,唯一比較特別的地方僅是你需要先從文件中找到自己需要的API,那以我的情況來說我會先以Synonyms作為關鍵字在頁面上做搜尋,下方的圖片就應該是你第一個需要找到的資訊。

day28-demo-image

因此我們知道可以透過https://api.datamuse.com/words?rel_syn={word}"這樣的url去取得需要的同義字,那麼接下來的事情就簡單多了。

強烈建議你先至少知道回傳的格式,隨便貼個word去call那隻api看看。

day28-demo-image-2

為了呈現題目要求的幾個東西,我第一個想法會是我需要以下的state進行管理
1. word => 使用者輸入的input
2. synonyms => 最終fetch到的所有同義字
3. isLoading => 用來顯示是否正在讀取中

下一步的話我會思考該怎麼處理fecth的部分,因為我們並不是希望一進頁面就開始抓資料,而是透過使用者點擊,不管是送出按鈕還是點擊產生的其中一個同義字,這就會是兩次相同的fetch行為,一般遇到這種情況我會選擇抽出邏輯讓頁面乾淨一些,我們這次就用一個custom hook來處理。

const BASE_URL = "https://api.datamuse.com/words";

function useFetchSynonyms() {
  const [synonyms, setSynonyms] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  const fetchSynonyms = async (word) => {
    setIsLoading(true);
    try {
      const response = await fetch(`${BASE_URL}?rel_syn=${word}`);
      const data = await response.json();
      setSynonyms(data);
    } catch (err) {
      console.log(err);
    } finally {
      setIsLoading(false);
    }
  };

  return { isLoading, synonyms, fetchSynonyms };
}

有了這個custom hook之後我們在App組件需要擔心的東西就變少了,只要在需要的地方呼叫hook內的fetchSynonyms函數並根據isLoading & synonyms陣列去做對應的渲染即可,如下方的做法。

import React, { useState } from "react";

const App = () => {
  const [word, setWord] = useState("");
  const { isLoading, synonyms, fetchSynonyms } = useFetchSynonyms();

  const handleSubmit = (e) => {
    e.preventDefault();
    fetchSynonyms(word);
  };

  const handleSynonymClick = (newWord) => {
    setWord(newWord); // 把input更新為點擊的同義詞
    fetchSynonyms(newWord); // 以新的詞抓取同義詞
  };

  return (
    <div className="App">
      <h1>Fetch all synonyms for given word</h1>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={word}
          onChange={(e) => setWord(e.target.value)}
          placeholder="Enter a word"
        />
        <button type="submit">Find Synonyms</button>
      </form>
      {isLoading ? (
        <p>Loading...</p>
      ) : (
        <ul>
          {!!synonyms.length &&
            synonyms.map((synonym, index) => (
              <li key={index} onClick={() => handleSynonymClick(synonym.word)}>
                {synonym.word}
              </li>
            ))}
        </ul>
      )}
    </div>
  );
};

export default App;

在上方的程式碼中我們用了兩個函數去處理請求的部分,並在渲染的地方判斷isLoading的值去決定是否渲染讀取中的狀態,最後我們只差找不到同義字時的處理而已。

這部分稍稍需要費一點工夫,你不能單純判斷synonyms是否為空陣列,因為還沒點擊任何東西前synonyms本身就會是一個空陣列,我們要做的是若搜尋後synonyms仍為空陣列,我們才顯示No synonyms found!的字樣。因此我會多加入一個state做這樣的管理,並稍稍修改我們handleSubmit函數,最終完整程式碼如下

import React, { useState } from "react";
const BASE_URL = "https://api.datamuse.com/words";

function useFetchSynonyms() {
  const [synonyms, setSynonyms] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  const fetchSynonyms = async (word) => {
    setIsLoading(true);
    try {
      const response = await fetch(`${BASE_URL}?rel_syn=${word}`);
      const data = await response.json();
      setSynonyms(data);
    } catch (err) {
      console.log(err);
    } finally {
      setIsLoading(false);
    }
  };

  return { isLoading, synonyms, fetchSynonyms };
}

const App = () => {
  const [word, setWord] = useState("");
  const [hasSearched, setHasSearched] = useState(false);
  const { isLoading, synonyms, fetchSynonyms } = useFetchSynonyms();

  const handleSubmit = async (e) => {
    e.preventDefault();
    await fetchSynonyms(word);
    setHasSearched(true); // 等上方請求完成後便將已搜尋的值更新
  };

  const handleSynonymClick = (newWord) => {
    setWord(newWord);
    fetchSynonyms(newWord);
  };

  return (
    <div className="App">
      <h1>Fetch all synonyms for given word</h1>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={word}
          onChange={(e) => setWord(e.target.value)}
          placeholder="Enter a word"
        />
        <button type="submit">Find Synonyms</button>
      </form>
      {isLoading ? (
        <p>Loading...</p>
      ) : (
        <ul>
          {hasSearched && !synonyms.length && <div>No synonyms found!</div>} // 加入找不到同義字的情況處理
          {!!synonyms.length &&
            synonyms.map((synonym, index) => (
              <li key={index} onClick={() => handleSynonymClick(synonym.word)}>
                {synonym.word}
              </li>
            ))}
        </ul>
      )}
    </div>
  );
};

export default App;

總結

今天的題目要求你根據指定的文件與指示完成題目的要求,過程中你可以透過抽取邏輯的方式精簡自己的程式碼,並不算太困難的問題,只要之前對於state & fecth的題目都有好好了解,今天的特別之處便只有要求你閱讀文件這一點,遇到這類的情況時記得想辦法快速找出自己需要的資訊並確認api的結果,這麼一來你才有辦法好好規劃你的組件!我們明天見囉,剩下兩個問題會是比較遊戲性的,敬請期待!

本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!


上一篇
30天React練功坊-攻克常見實務/面試問題 Day27: Add emojis to the page onclick PartII(interview question)
下一篇
30天React練功坊-攻克常見實務/面試問題 Day29: Simple Tic-Tac-Toe game(interview question)
系列文
30天React練功坊-攻克常見實務/面試問題30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言