React.js快速入門 — (5)Prop&State&Hook

Mackerel Chang
Mess up
Published in
9 min readFeb 3, 2020

Prop&State&Hook — React.js如何存取資料,針對16.8版後的React.js所製作的新手入門上手文章

結束了Component重要的章節後,接下來第二重要的功能:Prop&State&Hook,也乘載了所有生命週期動態更新的責任。

還記得在第二章Overview的這張圖片。

所有事情只要產生改變一定會進入 render 。若有呈現到網頁,都一定會不斷刷新到網頁上。

其中一部分就是在”更新時”階段,只要React.js的資料有所改變,就一定會觸發 render ,針對網頁結構做出改變。

以下是對於資料流生命週期會使用到的函式:

對於資料流整個生命週期

所有生命週期的步驟請熟記,它會協助你哪個時期會發生的事情。在做Debug(偵錯)的時候,也能比較了解是哪個環節出錯。

接下來使用資料的類型去詮釋生命週期的觸發:

Prop

在前幾個章節我們都能看到 prop 的身影,因為它協助我們將資料傳入Component。最重要的是它是Read-Only(唯讀)不隨意被更改的,畢竟更改它沒有意義,也沒法回傳給上層。

傳遞方式

在JSX使用Attribute(屬性)方式傳遞下去,注意屬性建議使用camelCase命名。

const name = "Hello";
const element = <Hello myName={name} />
function Hello(props){
return <h1>Hello, my name is {props.myName}</h1>;
}

(ES6) Class Component綁定

在Class Component,必須先在Class的 constructor() 繼承 props 的屬性。日後在 render() 就可以直接用 this.props 呼叫傳進來的參數。

class Hello extends React.Component{
constructor(props){
super(props);
}
render(){
return <h1>Hello, my name is {this.props.myName}</h1>;
}
}

State

state使用在(ES6) Class Component,必須在Class的 constructor() 先宣告好資料結構。它也跟 prop一樣是Read-Only的,我們使用 {this.state.<arg>} 時只能做讀取。寫入的時候必須用React.js替它設計的 setState() 完成。

State有以下事情需要注意:
1. State 又稱 Local state,只有呼叫它的物件或是Component擁有才能使用。除非是有上層下指令才能使上層一起擁有
2. 只要State一被修改,就一定會觸發 render() 更新頁面。

宣告

constructor() 用Javascript Dictionary型別宣告好資料結構

class Hello extends React.Component{
constructor(){
this.state = {name: ""};
}
}

設定資料

使用 setState() 完成檔案設定,括號裏頭使用Javascript Dictionary型式,不用將全部資料結構設定一遍。因為State是採用合併(merge)形式,它會找到相對應的欄位,並且做部分更新

假設我們宣告以下結構:

class Hello extends React.Component{
constructor(){
this.state = {name: "", audience: 0};
}
}

我們只要下以下指令,它就會只更新 name 的部分,並不會影響到 audience

this.setState({name: "Hello"});

React 可以將多個 setState() 呼叫批次處理為單一的更新,以提高效能。
Function 將接收先前的 state 作為第一個參數,並且將更新的 props 作為第二個參數

它也可以用Arrow Function與 prop 做結合,成為一種非同步更新:

this.setState((state, props) => ({
counter: state.counter + props.increment
}));

結合生命週期

上面我們講了資料設定,但沒有提及要在哪邊設定!原因是 state 並不會在 render() 做設定 ,它要配合一些HTML表單同步或者是生命週期才會使用。在上方提及的生命週期圖片的 can use this.setState() ,或是HTML的監聽函式才能使用。

我們可以將那些提供的函式呼叫做Override(覆寫):

class Hello extends React.Component{
// ...
componentDidMount(){
this.setState(...);
}
// ...
}

更多生命週期的使用請參閱官方文本,HTML表單則是於此

Hook

Hook 是 function,他讓你可以從 function component「hook into」React state 與生命週期功能。

在16.8版後誕生的功能,是在Function Component也能使用(ES6) Class Component的State。React.js在文本也說道,Javascript最大魔王之一無非就是運用 this 的概念。在一般函式、Prototype、ES6 Class、匿名函式、箭頭函式每個區域的 this 用法都不太一樣,容易造成寫手迷失使用方向。加上(ES6) Class Component有點像是過度包裝,當有好多個Component會覺得很複雜。

因此官方建議少用Class Component多使用Hook於Function Component。不過 Class Component還是要有些基礎概念,畢竟現在很多寫好的工具都還是用其,必須要看得懂才能妥善運用。

使用

Hook 只有兩種函式可以使用: useStateuseEffect

useState :如同 state 般的方法,傳進去的就是想儲存的資料。它會回傳兩個變數,一個是目前state,如下方的 count;另一則是更新state的函式,如下方的 setCount

function Counter({initialCount}) {
const [count, setCount] = useState(initialCount);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
</div>
);
}
  1. 因為 useState 回傳的是兩個變數組成的陣列,所以我們在接收端也掛上中括號就可以直接取這兩個變數。
  2. onclick因為屬性問題需設定成一個函式之後,才能呼叫 setCount
  3. setCount 會先回傳目前State count ,亦即裡面宣告的 prevCount

useEffect:和 componentDidMountcomponentDidUpdate,與 componentWillUnmount 有著同樣的宗旨,但整合進一個單一的 API。主要就是協助觸發除了更改 state 內容外任何想做的事。傳入的參數必須為一個函式,就可以開始做任何的事情。厲害的是,它可以不用到 this 的字眼,減少除錯的功夫。

useEffect(()=>{
// Do anything you want.
});

以上就介紹完 Hook所有基本的呼叫了!

注意

Hook 有兩件事情須注意:
1. 只能在 Function Component呼叫
2. 只能在 Function 最上層呼叫,所以for loop、if-else與Nested(巢狀) function都不能使用,這會影響到 useEffect 的使用,將在下方解釋。

function Top(){
// for loop
for(var i=0;...)
// if-else
if (){}else{}
// Nested function
function Sec(){}
const third = function(){}
}

React.js會去記住這個Component的Hook觸發順序,每一次的使用這函式的Hook必須是固定的。假如我們加上if-else在其中:

function sayMyName(){
const [name, setName] = useState('Mary');
if (name !== '') {
useEffect(function persistForm() {
// ...
});
}
}

會一下這次呼叫有 name的useStatepersistForm的useEffect ,可能下一次只剩 name的useState 。這會讓React.js不知道useEffect要怎麼去綁定。因此要使用if-else的方法就是放進去useEffect裏頭:

function sayMyName(){
const [name, setName] = useState('Mary');
useEffect(function persistForm() {
if (name !== '') {
// ...
}
// ...
});
}

這樣就能確保每一次都呼叫得到。

其他

React.js也提供可自行設定Hook

題外話,若未來想做登入狀態這種全域資料存取,可以翻閱進階指南的Context;Hook部分則是有 useContext

結語

在此,整個React.js快速入門的系列文章就告一段落了。對React.js有了初步印象,就開始建議前往二刷官方文本(安裝加上主要概念章節),讓整個概念組織起來。若對內容有任何問題或是需修正的,也請在每個文章下方留言告訴我。謝謝您的觀看💪

喜歡的話可以給我一點掌聲唷!

上一篇:React.js快速入門 — (4)Component

--

--

Mackerel Chang
Mess up
Editor for

專攻於 Local Style Transfer 的碩士生。副業是接觸前端網頁。偶爾發發論文筆記與React.js心得。 https://www.linkedin.com/in/ching-yu-chang-270747195/