React - 三大屬性 State
React - 三大屬性 State
前言
介紹組件 三大屬性中的 State 屬性,這裡還不會討論 Hook 運用。
React 起手式
老規矩,先建立一個 HTML,並搭建好環境
創建組件,完成基礎頁面
在 script 中,要引用 React 的三大屬性,若不考慮使用 Hook ,則需使用類式組件。
1
2
3
4
5
6class Vaccine extends React.Component {
render(){
return <h2>你打疫苗了嗎? 還沒QQ</h2>
}
}
ReactDOM.render( <Vaccine/>, document.getElementById( 'container' ) )畫面呈現
創建建構子,初始化狀態
在類式組件內添加建構子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class Vaccine extends React.Component {
// 建構子,寫 props 傳遞參數
constructor(props){
// 建構子內要寫 super 接收 props,不然會報錯
super(props)
// 初始化狀態,官方規定要寫物件型式
this.state = { vaccinated: true }
}
render(){
// 這裡把回答變成 JS 表達式 {},並使用用條件運算子
return (
<h2>你打疫苗了嗎?
{ this.state.vaccinated ? ' 已經打了(.▽.) b' : ' 還沒(Q A Q)' }
</h2>)
}
}
ReactDOM.render( <Vaccine/>, document.getElementById( 'container' ) )因為我們把
vaccinated:
設為true
,所以條件運算子就會選:
前面的字串。如果我們把
vaccinated:
改成false
,那麼條件運算子就會選擇:
後面的字串。這時打開開發者工具的 Component,可以看到
state
。最後再更進階一點,把代碼更加精簡,將
render
內提取狀態進行解構賦值,讓程式更容易閱讀。1
2
3
4
5
6
7
8
9render(){
// 在這裡先進行解構賦值,讀取狀態
const { vaccinated } = this.state
// 這樣後面就可以直接利用變數,不用再加前墜
return (
<h2>你打疫苗了嗎?
{ vaccinated ? ' 已經打了(.▽.) b' : ' 還沒(Q A Q)' }
</h2>)
}
嘗試為頁面新增互動
類式組件中方法的 this 指向?
幫頁面中的
<h2>
新增onClick
事件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class Vaccine extends React.Component {
constructor(props){
super(props)
this.state = { vaccinated: false }
}
render(){
const { vaccinated } = this.state
// 用來測試作為實例調用是否正常
this.changeVaccinated()
// 幫 <h2> 新增 onClick 事件,
// 需注意 React 的事件綁定改成用駝峰命名法,
// 並且調用方法要用 {} 包起來,
// 且要用 this 來調用函數,結尾不能加 ()
// 有加 () 會變成一開頁面就立即執行
return (
<h2 onClick={ this.changeVaccinated }>你打疫苗了嗎?
{ vaccinated ? ' 已經打了(.▽.) b' : ' 還沒(Q A Q)' }
</h2>)
}
/* 接續下面 */並在類式組件內增加
onClick
所需調用的函數1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/* 承接上面 */
// 將 changeVaccinated 放進 Vaccine 的原型變數裡,供實例使用
// 通過 Vaccine 實例調用 changeVaccinated 時
// 由於 changeVaccinated 是作為 onClick 的'回調函數'
// 所以不是通過'實例'調用,而是'直接'調用。
// 類中的方法默認開啟了局部的嚴格模式,
// 所以 changeVaccinated 中的 this 為 undefined
changeVaccinated(){
console.log(this)
}
}
ReactDOM.render( <Vaccine/>, document.getElementById( 'container' ) )點擊
你打疫苗了嗎?
後,打開開發者工具 Console ,觀察 this 回傳值總結 this 指向結果,作為
onClick
直接調用函數會無法指向實例。
解決類式組件中方法 this 指向的問題
只要在
constructor
中,多加一行程式碼就能解決 this 指向問題1
2
3
4
5
6
7
8
9
10
11
12class Vaccine extends React.Component {
constructor(props){
super(props)
this.state = { vaccinated: false }
// 增加這一行,解決 changeVaccinated 中的 this 指向
// 右邊的 this.changeVaccinated 會先找到自身原型上的 changeVaccinated
// 調用了 bind(this) 方法,並把 this 綁在實例身上
// 然後將這個方法放到自身新增的 changeVaccinated (左邊)
this.changeVaccinated = this.changeVaccinated.bind(this)
}點擊
你打疫苗了嗎?
後,打開開發者頁面的 Console,就會看到 this 指向實例,並且添加了changeVaccinated
方法![bind(this) 解決指向問題]](https://i.imgur.com/jJl2WYw.png)
這段程式碼整個流程如下圖
bind() 方法做了什麼?
bind() 方法做了兩件事
1. 會建立一個新的函數。
2. 會幫你改函數裡面的 this
小測驗
1 |
|
A 和 B 答案分別是甚麼 不知道的話請點我
1 |
|
嘗試新增互動,剛學 React 必踏入過一次的坑
首先取得 state 裡面的
vaccinated
值1
2
3changeVaccinated(){
const vaccinated = this.state.vaccinated
}嘗試修改 state
1
2
3
4
5
6changeVaccinated(){
const vaccinated = this.state.vaccinated
this.state.vaccinated = !vaccinated
// 用來測試是否有更改值
console.log(this.state.vaccinated)
}你會發現值確實有修改,但畫面不會變
注意狀態( state )不可以直接修改
this.state.vaccinated = !vaccinated
這行就是直接修改
使用 setState 來修改狀態
一樣先取得 state 裡面的
vaccinated
值1
2
3changeVaccinated(){
const vaccinated = this.state.vaccinated
}使用 setState() 方法,
注意狀態( state )必須透過 setState 進行修改1
2
3
4changeVaccinated(){
const vaccinated = this.state.vaccinated
this.setState({ vaccinated: !vaccinated })
}這時畫面就能點擊切換
state 的簡寫方式
使用類的基礎知識簡化 state
這是原來的程式碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23class Vaccine extends React.Component {
constructor(props){
super(props)
this.state = { vaccinated: false }
this.changeVaccinated = this.changeVaccinated.bind(this)
}
render(){
const { vaccinated } = this.state
return (
<h2 onClick={ this.changeVaccinated }>你打疫苗了嗎?
{ vaccinated ? ' 已經打了(.▽.) b' : ' 還沒(Q A Q)' }
</h2>)
}
changeVaccinated(){
const vaccinated = this.state.vaccinated
this.setState({ vaccinated: !vaccinated })
}
}
ReactDOM.render( <Vaccine/>, document.getElementById( 'container' ) )將 constructor 中的 state 拉出來
- 類中可以直接寫賦值語句 = 往實例裡面追加屬性
1
2
3
4
5
6
7
8
9
10
11
12class Vaccine extends React.Component {
constructor(props){
super(props)
// this.state = { vaccinated: false }
this.changeVaccinated = this.changeVaccinated.bind(this)
}
// 使用賦值語句,拉出 constructor
state = { vaccinated: false }
/* 以下省略 */將函數改成賦值語句 + ES6 箭頭函數的寫法,並省略 constructor 裡面的 bind()
利用箭頭函數的特點
- 沒有自己的 this
- 使用 this 時,會找其外側函數的 this,作為箭頭函數 this 去使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14/* 以上省略 */
// changeVaccinated(){
// const vaccinated = this.state.vaccinated
// this.setState({ vaccinated: !vaccinated })
// }
// 改成 ES6 箭頭函數
changeVaccinated = () => {
const vaccinated = this.state.vaccinated
this.setState({ vaccinated: !vaccinated })
}
}
ReactDOM.render( <Vaccine/>, document.getElementById( 'container' ) )省略整個 constructor,最後簡化結果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class Vaccine extends React.Component {
// 初始化狀態
state = { vaccinated: false }
render(){
const { vaccinated } = this.state
return (
<h2 onClick={ this.changeVaccinated }>你打疫苗了嗎?
{ vaccinated ? ' 已經打了(.▽.) b' : ' 還沒(Q A Q)' }
</h2>)
}
// 自定義方法 - 藥用賦值語句的型式 + 箭頭函數
changeVaccinated = () => {
const vaccinated = this.state.vaccinated
this.setState({ vaccinated: !vaccinated })
}
}
ReactDOM.render( <Vaccine/>, document.getElementById( 'container' ) )
總結 State
什麼是 State ?
- State 是組件中最重要的屬性,值是物件(可以包含多個 key-value)。
- 通過更新 State 重新渲染組件。
State 必須注意的要點
組件中 render 方法中的 this 為組件的實例物件。
組件自訂義的函數中,this 為
undefined
如何解決?- 強制綁定 this:通過函數
bind()
方法 - 賦值語句 + 箭頭函數
- 強制綁定 this:通過函數
狀態資料,不能直接修改或更新,必須借助
setState()
來更新