Skip to content

Instantly share code, notes, and snippets.

@coodoo
Last active November 7, 2020 13:42
Show Gist options
  • Save coodoo/e8a5aec60c2cf3bd52e4ffe45e7dbe75 to your computer and use it in GitHub Desktop.
Save coodoo/e8a5aec60c2cf3bd52e4ffe45e7dbe75 to your computer and use it in GitHub Desktop.

前言

這是 Oct. 28 ~ Nov. 01, 2020 間於推特上舉辦的趣味面試挑戰,四天期間共 517 人次閱讀、42 人 fork sandbox,最後收到九份回答,如果這是正式面試,將錄取 5 人、備取 1 人、拒絕 3 人,也就是成功率約六成。

先說結論

  • 面試時別急著跳進去回答問題,先拉高層次觀察問題的形狀,搞清楚 root cause 後再思考答案與解法

  • 過程中多詢問主考官真正想達到的目地、目前為何採取此手法、現在的做法是否遇到困難、有無解法上的限制(time, mem, cpu bound)

  • 這些解題中的思考與發問過程與最終提供正確解法一樣重要(甚至可能成為最後勝出關鍵)

觀察

  • 大部份人都能抓出兩個錯誤: typo & state sync

Typo

  • 首先是 e.target.value 寫錯為 e.value 導致文字框出現錯誤

  • 這很好解決,改掉錯字就好了

  • 有位同學建議不如就改用 uncontrolled input 做下去,但未提供改用此方式後的可能優、缺點

State sync

  • 其次是識別出這是個全域狀態(context)轉為區域狀態(useState)間的同步問題

  • 大部份人提供的解法都是改為直接操作 setContext() 一律更新全域狀態以解決同步問題

  • 少部份人提到用 useEffect(fn, [context]) 來同步 context 與 state 狀態

  • 更少的人提到可用 key={context} 的方式來強迫重置元件

但只有非常少的人考慮到為何一開始會採取 state sync 解法

  • 也就是詢問主考官一開始這樣設計是否為了滿足某種業務需求?

  • 以此例來說,採取 state sync 是因為 ComponentB 需要頻繁編輯內容與更新畫面,因此不希望直接操作 setContext 造成整支 app 一起更新

  • 也因此直接改用 setContext 雖能解決眼前問題,但可能造成其它效能問題

加分項目

  • 如果有考慮到編輯需求而決定採用 state sync 解法,記得要先 benchmark 兩種手法的效能,說不定在 app 架構不大、VDOM tree 不夠深的情況下,兩種解法其實效能一樣,那就可安心採用簡單又可靠的 setContext

    • 這就是 Premature Optimization Is the Root of All Evil 的由來
  • 如果建議改用 redux,可主動說明 redux 的 selector 可如何防止 app 更新效能劣化

  • 如果建議改用 reducer,可進一步建議區隔多份 context 以減少整支 app 重繪的問題

建議

  • 愷開大大 慷慨公開他的解答,值得參考(當然 svelte 也是未來五年最值得觀察的新星💪)。

  • 提出任何解法都應能解釋其帶來的正、反面影響與適用的情境,如有不明瞭的地方立即向考官提問與討論。

  • 答題時盡量用字精簡直切要害、減少多餘贅字並口吻充滿自信,盡量別用呵呵大概...吧等不確定用語,會影響專業形像。

  • 如果是 take home 試卷,答題完務必多次檢查確認程式能正確執行,console 內也沒出現錯誤訊息,否則只顧炫技最後程式出錯就得不償失。

  • 面試過程中很大部份是觀察對方 active reasoning 的能力而非解題速度,因此盡量爭取時間思考、提問與討論,別急著回答,通常是較佳策略。

  • 如果真的不懂,就直接承認,不要鬼扯,可進一步尋求考官提供建議與可能的解題方向。

  • 從投稿中提供的解法可清楚看出哪些人是 junior 等級,只會依照 textbook answer 來解題,並且通常對問題的觀察還不夠高層與透徹無法找到 root cause,這部份還有很大進步空間。

後記

  • e.value 其實真的只是 typo,但在面試題中埋小錯誤也是常見的手段。

  • 但如此做重點不是看對方能否快速找出與修正,而是觀察對方面對錯誤時的處理態度,例如除錯過程與手法是否合理。

/* eslint-disable */
import React, { useState, useContext, useEffect } from "react";
import "./styles.css";
export const Context = React.createContext();
/*
# 目標
1. 用戶可修改文字框的值
2. 按下 Change Value 鈕也能改變文字框的值
# 答題方式
1. 請 fork 此 sandbox 並於註解中回答下列問題
2. 請同時提供修正後程式
3. 將答案的 sandbox 私訊傳給 @thecat
# 題目
1. 請描述發生的問題? (1分)
a. 打字無法更新文字框內容,並出現錯誤訊息
b. 按鈕無法設定新值到文字框
2. 發生問題的原因? (1分)
a. e.value 應為 e.target.value 之 typo
b. global context 只會在第一次 render 時放入 local state
3. 針對此問題的解法? (1分)
a. 修正 typo 為 e.target.value 即可
b. 第二次之後要靠 useEffect() 來持續同步 global/local state
4. 是否有其它方式可從根本避免此問題發生? (1分)
- prop drilling 由外而內層層傳遞參數
- 統一使用全域 setContext() 更新狀態
- 使用 redux 等外部狀態管理工具
- 將 key 綁定 context 強迫每次重置元件以重跑 useState()
5. 有其它想法或觀察嗎? (1分)
- 為何一開始要採用 global context -> local state 同步的手法?
- 是為了解決某種業務需求嗎?
- 如果是,採用此手法後遇到什麼問題?
- 一律用 setContext 可能有效能隱憂,專案對此的容忍度有多大?
Last updated: Oct. 29, 2020
*/
function ComponentB() {
const [context, _] = useContext(Context);
const [data, setData] = useState(context);
useEffect(() = {
setData(context)
}, [context])
return (
<div>
<div>Context value: {data}</div>
<input type="text" value={data} onChange={(e) => setData(e.target.value)} />
</div>
);
}
function ComponentA() {
const [_, setContext] = useContext(Context);
return (
<button onClick={() => setContext(Math.random().toString())}>
Change Value
</button>
);
}
export default function App() {
const [context, setContext] = useState("initial value");
return (
<Context.Provider value={[context, setContext]}>
<ComponentB />
<ComponentA />
</Context.Provider>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment