React - 三大屬性 State
React - 三大屬性 State
![]()
前言
介紹組件 三大屬性中的 State 屬性,這裡還不會討論 Hook 運用。
React 起手式
-
老規矩,先建立一個 HTML,並搭建好環境
創建組件,完成基礎頁面
-
在 script 中,要引用 React 的三大屬性,若不考慮使用 Hook ,則需使用類式組件。
class Vaccine extends React.Component { render() { return <h2>你打疫苗了嗎? 還沒QQ</h2> } } ReactDOM.render(<Vaccine />, document.getElementById('container')) -
畫面呈現

創建建構子,初始化狀態
-
在類式組件內添加建構子
class 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內提取狀態進行解構賦值,讓程式更容易閱讀。render(){ // 在這裡先進行解構賦值,讀取狀態 const { vaccinated } = this.state // 這樣後面就可以直接利用變數,不用再加前墜 return ( <h2>你打疫苗了嗎? { vaccinated ? ' 已經打了(.▽.) b' : ' 還沒(Q A Q)' } </h2>) }
嘗試為頁面新增互動
類式組件中方法的 this 指向?
-
幫頁面中的
<h2>新增onClick事件class 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所需調用的函數/* 承接上面 */ // 將 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 指向問題class 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
小測驗
class Youtube extends React.Component {
constructor(props) {
super(props)
this.state = {
subscribed: false,
youtube: 'https://www.youtube.com/channel/UC-b2nGm0xLzic38Byti0VjA',
}
this.____A____ = this.____B____.bind(this)
}
render() {
const { subscribed, youtube } = this.state
return (
<h2 onClick={this.subscribe}>
你訂閱六角學院的 Youtube 了嗎?
{ subscribed
? ' σ`∀´)σ 訂閱了,哪次不訂閱'
: ` 我就幫到這了(ㆆᴗㆆ) ${youtube}` }
</h2>
)
}
gogogo() {
console('趕快去唄 =͟͟͞͞( •̀д•́)')
}
}
ReactDOM.render(<Youtube />, document.getElementById('container'))A 和 B 答案分別是甚麼 不知道的話請點我
右邊有答案-----------------------------------------------------------------------------A: subscribe / B: gogogo!
嘗試新增互動,剛學 React 必踏入過一次的坑
-
首先取得 state 裡面的
vaccinated值changeVaccinated(){ const vaccinated = this.state.vaccinated } -
嘗試修改 state
changeVaccinated(){ const vaccinated = this.state.vaccinated this.state.vaccinated = !vaccinated // 用來測試是否有更改值 console.log(this.state.vaccinated) } -
你會發現值確實有修改,但畫面不會變

-
注意狀態( state )不可以直接修改
this.state.vaccinated = !vaccinated這行就是直接修改
使用 setState 來修改狀態
-
一樣先取得 state 裡面的
vaccinated值changeVaccinated(){ const vaccinated = this.state.vaccinated } -
使用 setState() 方法, 注意狀態( state )必須透過 setState 進行修改
changeVaccinated(){ const vaccinated = this.state.vaccinated this.setState({ vaccinated: !vaccinated }) } -
這時畫面就能點擊切換

state 的簡寫方式
使用類的基礎知識簡化 state
-
這是原來的程式碼
class 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 拉出來
- 類中可以直接寫賦值語句 = 往實例裡面追加屬性
class 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 去使用
/* 以上省略 */ // 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,最後簡化結果
class 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()來更新