
2024/6/11
React HooksuseRef 和 forwardRef
為什麼要使用 useRef
和 forwardRef
?
useRef
- 可以維持元件的狀態,並且不會觸發重新渲染。
- 可以用來控制DOM元素,例如:focus、scroll、play、pause等。
程式碼範例如下:
function MyComponent() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus(); // 自動聚焦
}, []);
return <input ref={inputRef} />;
}
forwardRef
- 可以將ref傳遞到子元件。
- 如果不使用
forwardRef
,React會報錯
程式碼範例如下:
// 定義一個 FancyButton 組件,使用 forwardRef 將 ref 傳遞下去
const FancyButton = forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
function App() {
const buttonRef = useRef(null);
const handleClick = () => {
if (buttonRef.current) {
buttonRef.current.focus(); // 使用 ref 來聚焦按鈕
}
};
return (
<div>
<FancyButton ref={buttonRef}>Click me!</FancyButton>
<button onClick={handleClick}>Focus Fancy Button</button>
</div>
);
}
同場加映:useImperativeHandle
目的是限制暴露的方法給父元件來做使用
// 定義一個自定義輸入框組件,使用 forwardRef 傳遞 ref
const CustomInput = forwardRef((props, ref) => {
const inputRef = useRef();
// 使用 useImperativeHandle 來暴露 focus 方法給父組件
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} {...props} />;
});
function ParentComponent() {
const inputRef = useRef();
const handleClick = () => {
inputRef.current.focus(); // 使用 ref 來聚焦輸入框
};
return (
<div>
<CustomInput ref={inputRef} placeholder="Click the button to focus" />
<button onClick={handleClick}>Focus Input</button>
</div>
);
}
說明:
- 自定義輸入框組件 CustomInput:使用 forwardRef 來接收 ref 並將其傳遞給內部的 input 元素。
- 使用 useImperativeHandle:這允許我們在父組件中自定義暴露的方法(如 focus)。
- 父組件 ParentComponent:使用 useRef 來創建 ref,並通過按鈕點擊觸發輸入框的聚焦。

2024/3/6
React HookReact-Hook-useContext
useContext 是一個 React Hook,因為React為單向資料流的特性,所以當我們需要在不同的 component 之間共享資料時,我們通常會透過 props 來傳遞資料,但是當 component 的層級越來越深時,這樣的寫法會變得非常麻煩,這時候 useContext 就可以派上用場,作為一個傳送門useContext可以像下圖中自由的傳遞props。
Ref:dev.react.com
使用方式
1.建立一個 空的context並且導出
常見作法是在建立一個新的檔案中建立一個空的context並且導出,檔名可以隨意取名。
import { createContext } from 'react';
export const MyContext = createContext(null);
2.在最上層的component中使用Provider,並包裹住想要傳遞的元件,傳遞想要傳入的porps
import { MyContext } from './useContext.jsx'
let AAA="132"
<MyContext.Provider value={{AAA}}>
<App />
</MyContext.Provider>
3.可以在porvider包裹住的情況下,使用useContext來取得資料
import { MyContext } from "./useContext.jsx";
const {AAA}=useContext(MyContext)

2024/1/11
React HookReact Hook-useMemo
前言
根據 React 官方文件中的說明,useMemo 會在渲染期間記住傳入的函式,並且在渲染期間避免重複執行該函式。
什麼時候使用 useMemo
官方文件也強調你應該僅僅把 useMemo 作為性能優化的手段。如果沒有它,你的程式碼就不能正常運作,那麼請先找到潛在的問題並修復它。然後再添加 useMemo 以提高性能。
useMemo 的使用方式
useMemo(calculateValue, dependencies)
calculateValue:裡頭帶一個 callback 並寫入需要處理的函式
dependencies:依賴的值,當這個值改變時,useMemo 才會重新執行
const result = useMemo(() => {
add(countA);
}, [countA]);
useMemo 的使用場景
如下方的例子,如果沒有使用 useMemo,當我們點擊 countB 按鈕時,同樣會執行 add 函式,但是我們只想要 countA 改變時才執行 add 函式,因為我們只在乎 result 的結果而在下方範例中 result 又只有跟 countA 有關係,這時候就可以使用 useMemo 來避免重複執行 add 函式。
但是附帶一提,其實沒有使用 useMemo 也不會有什麼問題,因為 就頂多是重複執行 add 函式而已,但是如果 add 函式是一個很耗時的函式,那麼就會造成效能上的問題,這時候就可以使用 useMemo 來避免重複執行 add 函式。
function add(n) {
console.log("我被執行了");
return n * n;
}
function App() {
const [countA, setCountA] = useState(0);
const [countB, setCountB] = useState(0);
const result = useMemo(() => {
add(countA);
}, [countA]);
return (
<>
<button
onClick={() => {
setCountA((countA) => countA + 1);
}}
>
count is {countA}
</button>
<button
onClick={() => {
setCountB((countB) => countB + 1);
}}
>
count is {countB}
</button>
<p>{result}</p>
</>
);
}

2024/1/9
React JavaScriptDay 30 遲來的完賽

2024/1/2
React JavaScriptDay 29 React的本質-Library
雖然 React 現在被稱作 3 大框架其中之一,但是如果現在打開 React 的官網,會發現它的定位是一個 Library,而不是一個 Framework,事實上 React 確實保持著高度靈活性,讓開發者可以自由的選擇其他的 Library 來搭配使用,這也是為什麼 React 能夠在短短幾年內就成為主流的原因之一。甚至在搭配的套件上也有許多不同的選擇,像是 Redux、React-Router、React-Bootstrap 等等,這些套件都是為了滿足不同的需求而生的,而且都是由社群開發的,這也意味著 React 的生態系非常的豐富,而且也有許多的資源可以參考,這也是 React 能夠快速成長的原因之一。今天就來試著用一個簡單的例子來說明 React 的本質吧!
使用 CDN 引用 React
跟許多其他的 Library 一樣,React 也可以透過 CDN 的方式來引用,這樣就不需要透過 npm 或是 yarn 來安裝,,只需要在 HTML 中引用 React 的 CDN 就可以使用了,以下是範例,可以直接複製貼上到 HTML 中,然後用套件 liveserver 打開就可以看到 console 結果了。可以看到 React 跟 ReactDOM 可以是使用的方法,而且還有 babel,這是因為 React 的語法是 JSX,所以需要 babel 來轉換成 JavaScript 才能執行。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="rrot"></div>
<script
crossorigin
src="https://unpkg.com/react@18/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
console.log(React, ReactDOM);
</script>
</body>
</html>
React CDN 使用範例
接續上一個例子,這次就來試著使用 React 的元件吧!首先要先創造一個元件,然後再把它渲染到 root 根元素上,以下是範例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script
crossorigin
src="https://unpkg.com/react@18/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
// 創造元件
const App = () => {
return (
<div>
<h1>Hello World</h1>
</div>
);
};
// 把App元件渲染至root根元素
ReactDOM.render(<App />, document.getElementById("root"));
</script>
</body>
</html>
總結
大家可以發現,我這裡只是單純的使用 HTML 而已,並沒有使用太複雜的環境建置工具,雖然實務上不會這樣使用,但是我這裡只是想要表達 React 並不是那麼的難以接近,在官方定義成 library 的前提下,至少在一開始的學習上心態上可以抱持輕鬆一點的態度,不用太過於緊張。

2023/10/12
React JavaScriptDay 28 React 的 Hello World-Hook-useState
要說 React 有什麼特別的地方我覺得應該就是 HooK 了吧!Hook 是在 React 16.8 版中加入的,hook 有很多種,每一種的功能都不太一樣,甚至還可以自定義,簡單來說它就是函式,然後可以重複一直使用。但其實這是一個有點抽象的概念,所以就直接從實際的例子來了解吧!
什麼是 useState?
這是 React 最基本的一個 hook 之一,它的作用是儲存某個變數的狀態;並設定更新它的方法,基本寫法如下:
const [變數名稱, set變數名稱] = useState(初始值);
有三點需要注意: 1.需要依照小駝峰的規則撰寫 2.盡量給初始值,也就是變數名稱最一開始的狀態 3.變數只能被 set 變數做改變,使用方法就是在裡面塞一個更新後的數值
以下舉個例子:
宣告一個名為 count 的變數,此變數只能透過 setCount 做改變,且初始值為 0
const [count, setCount] = useState(0);
setCount(1); //更新此變數為1
useState 的作用?
因為在 React 中,不應該直接修改元件函式內部的變數,因為這不會觸發重新渲染元件。必須要使用 React 提供的狀態管理來處理這類情況,所以下面的例子:來展示其中差異
1.沒使用 useState:畫面的按鈕會沒有作用
function App() {
let a = 0;
return (
<>
<button
onClick={() => {
a = a + 1;
}}
>
按鈕
</button>
<h1>現在數值:{a}</h1>
</>
);
}
export default App;
2.使用 useState:才能改變狀態
function App() {
const [a, setA] = useState(0);
const handleIncrement = () => {
setA(a + 1);
};
return (
<>
<button onClick={handleIncrement}>按鈕</button>
<h1>現在數值: {a}</h1>
</>
);
}
export default App;
總結
在 React 中與畫面有關的變數都需要 useState 來做一個所謂的狀態管理,才能觸發重新渲染畫面,而且這個變數只能透過跟它同組宣告變數的方法做改變。

2023/10/11
React JavaScriptDay 27 React 的純函數元件
今天要解釋的東西會比較無聊乏味一點,但在 React 元件化導向的框架裡卻是一個很重要的概念,因為元件具有可以重複使用的特性,所以如果不是純函示會有一些 Bug 存在。
純函式的特性
純函式是一個在軟體開發中的重要概念,它有以下主要特點:
相同的輸入始終產生相同的輸出: 當你將相同的輸入值傳遞給一個純函式時,它始終會返回相同的輸出,不受外部狀態的影響。這種可預測性對於測試和除錯非常重要,因為你可以確信函式的行為不會因為外部狀態的改變而變化。
不會修改外部狀態: 純函式不會修改或影響除了它的輸入參數以外的任何狀態。這意味著它不會修改全域變數、不會修改傳遞給它的物件或陣列,也不會修改任何外部狀態。
沒有副作用: 純函式不會引起任何副作用,如改變資料庫的數據、發送 HTTP 請求、修改文件系統等。它僅僅是通過計算返回一個值。
可組合性: 由於純函式不依賴於外部狀態,它們非常容易組合在一起建構更複雜的邏輯。這種特性使得代碼更容易維護、測試和重用。
解釋了那麼多,我相信大家看了眼睛都花了而且一頭霧水,簡單舉例如下:
這就是一個純函式,不會修改外部狀態、沒有副作用、相同輸入有相同輸出
function add(a, b) {
return a + b;
}
這個 add
函式是純函式,因為它始終返回相同的輸出(兩個數字的和),不修改外部狀態,也不產生副作用。
那不是純函式又會發生什麼事呢?範例如下:
let total = 0;
function addToTotal(num) {
total += num;
return total;
}
console.log(addToTotal(3)); // 第一次呼叫,返回 3
console.log(addToTotal(3)); // 第二次呼叫,返回 6
這就不是一個純函式,因為它會改變外部狀態而且,相同的輸入得到不同的輸出。
那想一想如果它是一個元件,我們重複使用三次會發生什麼事?
範例如下:
let total = 0;
function AddToTotal() {
total += 1;
return <h2>{total}</h2>;
}
function App() {
return (
<div>
<h1>引入第一次</h1>
<AddToTotal /> //2
<h1>引入第二次</h1>
<AddToTotal /> //4
<h1>引入第三次</h1>
<AddToTotal /> //6
</div>
);
}
export default App;
就會發現明明就是引入同一個元件,但是會產生不同的結果,這會在重複使用這個元件特性上,造成無法預期的錯誤,所以 react 會鼓勵元件的寫法都要以純函式為主。
總結
雖然無聊或是繁瑣,但是如果發生想不到的錯誤就來檢查看看是不是純函式的問題,但後續其實有相對應的解法,但也續本系列不會提到,但是不純的函式在 react 元件中應該盡量被避免的。

2023/10/10
React JavaScriptDay 26 React 的多重渲染-列表與 Key
在 react 使用遍歷陣列的方法來呈現畫面是挺常見的,我們今天想要呈現一個陣列裡面的資料如下:
const tasks = [
{ id: 1, text: "看完 React的文件 " },
{ id: 2, text: "寫一篇部落格文章" },
{ id: 3, text: "學習 JavaScript" },
];
基本上我們不可能一個一個複製貼上,所以會利用 JSX 的 JavaScript 方法,去讀取資料並呈現畫面,有點像是 PHP 那樣的感覺。看範例寫法如下:
function App() {
const tasks = [
{id: 1, text: "看完 React的文件 "},
{id: 2, text: "寫一篇部落格文章"},
{id: 3, text: "學習 JavaScript"},
];
return (
<div>
<h1>我的任務清單</h1>
<ul>
{tasks.map((task) => (
<li key={task.id}>{task.text}</li>
))}
</ul>
</div>
);
}
export default App;
上面的範例是使用 map 的方法,不過這裡使用 forEach 也可以,差異是 map 會回傳新陣列但是 forEach 不會,至於 React 中為什麼會慣用 map 的原因與 hook 中的 useState 有關,這裡就先不多做贅述。
key 值的作用
仔細看上述的程式碼,會發現與正常遍歷陣列的方法不同的是多了一個 Key 值,它的作用是讓 react 能區別每一筆資料,雖然如果不給 key 值 react 會預設 index 當作 key 值,但是這不是一個好的寫法,因為可能會產生不穩定性(像是在對陣列操作增加、刪除之類的),造成渲染畫面的不確定性。
所以設定 key 值需要注意以下條件: 1.唯一性 2.必須從外部設定,不要再遍歷函示產生 3.不能隨意地被改變
總結
以上就是渲染陣列物件基本的方法,而且會與後續在使用 Hook 的順暢度會有直接的關係。
參考資料

2023/10/8
React JavaScriptDay 25 React 的選擇渲染-JSX 與條件控制的關係
說到 JavaScript 的流程控制大家很容易聯想到 if…else…或是三元運算子,在 JSX 裡面可以利用這些流程控制來選選擇性的呈現想要渲染的畫面。
官網分別介紹三種:
1.if..else 2.三元運算子(條件式 ? True 的結果 :False 的結果) 3.邏輯運算子(&&)
用 if…else..控制元件出現
這我相信能看到這裡的,大家都對這個語法很熟,但在 React 寫法就變成下面這樣,如果 number=”A”就會 return 並渲染 “AAA”,除此之外會 return 並渲染 “BBB”。
export default function App() {
let number = "123";
if (number === "A") {
return (
<>
<h1>AAA</h1>
</>
);
} else {
return (
<>
<h1>BBB</h1>
</>
);
}
}
條件運算子
ES6 的語法,簡單來說就是 if else 的簡化版,但是略有些差異以及特性,這裡就不先多提,因為在這裡兩者幾乎是等效的。
它由一個?和:組成基本架構如下:
條件式 ? 條件式為真要輸出的結果 : 條件式為假的時候要輸出的結果;
如果更改上述的範例為三元運算子的寫法如下:
export default function App() {
let number = "A";
return number === "A" ? <h1>AAA</h1> : <h1>BBB</h1>;
}
或是這樣
export default function App() {
let number = "A";
return (
<>
{number === "A" ? <h1>AAA</h1> : <h1>BBB</h1>}
</>
)
看起來更為簡單一點,可是在對於剛接觸的人比較不容易閱讀,要注意的一點
三元運算子是運算子它不是陳述式所以可以寫在 jsx 的{}裡,但是 if…else 則不行
邏輯運算子(&&)
這部分的寫法就更為簡單一點,但是適用的情況也不太一樣,比較適用決定是否要呈現元件,而不是選擇性呈現,寫法如下
export default function App() {
return <>{true && <h1>AAA</h1>} </>;
}
總結
雖然這三種寫法都是在做元件的選擇性渲染,但其實每一種方法適用的情境略有不同,需要依照適合的狀況,選擇適合的寫法:
- 使用 if…else 時,可以處理較複雜的條件邏輯。
- 三元運算子 提供了簡潔的寫法,適用於簡單的條件選擇。
- 邏輯運算子 (&&) 適合單一條件,不需要額外 else 或 return null。
參考資料

2023/10/7
React JavaScriptDay 23 React 中的 JavaScript
今天要介紹的是 JSX 重要的部分,就是如何在 JSX 中寫 JavaScript,其實很理所當然的 JSX 來就是 JavaScript,所以能寫 JavaScript 是一件蠻合理的一件事情,但依然有些規則需要遵守。接下來就依序來介紹吧!
1.使用大括號{}處理 Javascript
(1) 像是變數或是函式都可以在大括號裡被使用舉例如下:
function App() {
const name = "AAA";
return (
<>
<p>My name is {name} </p>
</>
);
}
export default App;
(2) 大括號的使用範圍
- 標籤內的文本
<p>My name is {name} </p>
- 在=後面的屬性
<src={picture} img/>//pictrue可能為一個變數
2.使用 CSS inline styles
需要使用兩層大括號,第一層是 JSX 要使用 JavaScript 規定的;第二層是因為 inline styles 被當作一個物件傳遞所以有大括號
<p style={{color: "white", backgroundColor: "black"}}>My name is {name} </p>
3.在大括弧中放表達式,不能陳述式
首先來複習一下什麼式表達式,可回傳一個結果的程式片斷就是一個表達式簡單來說,下列就是一個表達式,因為 console.log 會回傳 3
1 + 2;
為什麼會突然提這個呢?因為常用流程控制 if else 就是陳述式,所以這樣寫會報錯的喔!下面就是一個很經典的例子,這裡先留一個梗後續的文章會在說明,簡單來說三元運算子不是陳述式。
- 錯誤示範
function App() {
const a = "true";
const b ="false"
const judge = true;
return (
<>
{if(judge){
{a}
}else{
{b}
}}
</>
);
}
export default App;
- 正確示範
function App() {
const a = "true";
const b = "false";
const judge = true;
return <>{judge ? a : b}</>;
}
export default App;
總結
今天的重點其實很簡單,要寫 JavaScript 就在{}裡面寫就對了,但不能寫陳述式。