ItIron2023
react
昨天我們完成了add emoji onclick的問題,額外用了幾個state以及timer去達到題目的要求,今天我們來看另一個有趣的情境面試題吧!
請觀察這個codesandbox以及下方的instructions。
建立一個React應用程式,讓用戶輸入一個單詞,然後獲取並顯示該單詞的同義詞。當用戶點擊一個同義詞時,輸入和顯示的列表應更新為新單詞。
以下為一些注意事項
1. 請閱讀這份文件並找出對應的api自行使用
2. 讀取時與找不到同義字時應有對應的文字提示
3. 請勿使用其他第三方的套件
最終期待呈現的結果如下圖。
請以下方的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作為關鍵字在頁面上做搜尋,下方的圖片就應該是你第一個需要找到的資訊。
因此我們知道可以透過https://api.datamuse.com/words?rel_syn={word}"
這樣的url去取得需要的同義字,那麼接下來的事情就簡單多了。
強烈建議你先至少知道回傳的格式,隨便貼個word去call那隻api看看。
為了呈現題目要求的幾個東西,我第一個想法會是我需要以下的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的結果,這麼一來你才有辦法好好規劃你的組件!我們明天見囉,剩下兩個問題會是比較遊戲性的,敬請期待!
本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!