React - 高階函數柯里化

React - 高階函數柯里化

從 0 開始學 React

什麼是高階函數?

函數只要符合下面其中一點,就是高階函數

  • 如果函數接收的參數是一個函數
  • 如果函數調用的返回值依然是一個函數

常見的高階函數:PromisesetTimeoutArray.map

函數柯里化

通過函數調用,繼續返回函數的方式,實現多次接收參數,最後一起處理的函數形式

還沒優化受控組件的 onChange

以受控組件表單為例

  • 有多少個輸入框,就有多少個方法
  • 每個方法都是做重複的一件事情,把值存入狀態裡
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
state = {
username: '',
password: '',
}
// #1 保存帳號到狀態裡
saveUsername = (event) => {
this.setState({username: event.target.value})
}
// #2 保存密碼到狀態裡
savePassword = (event) => {
this.setState({password: event.target.value})
}
handleSubmit = (event) => {
event.preventDefault();
const { username, password } = this.state; // 從狀態取值
alert(`你的帳號是 ${username} 密碼是 ${password}`);
}
render(){
return(
<form action="https://www.google.com.tw/" onSubmit={ this.handleSubmit }>
<label for="username">帳號:</label>
<input
onChange={this.saveUsername}
type="text" id="username" name="username"/><br/>
<label for="password">密碼:</label>
<input
onChange={this.savePassword}
type="password" id="password" name="password"/><br/>
<button>登入</button>
</form>
)
}

使用柯里化方法

  1. 優化onChange方法,將功能相同,參數不同的方法變成一個

    • 首先理解綁定事件的回調函數
      • 回調函數不加()是把函數做為回調函數
      • 回調函數若加(參數)則是把返回值做為回調
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <label for="username">帳號:</label>

    // 把 onChange 的函數變成一樣的,並透過參數來區別
    <input
    onChange={this.saveFormData('username')}
    type="text" id="username" name="username"/><br/>
    <label for="password">密碼:</label>

    // 把 onChange 的函數變成一樣的,並透過參數來區別
    <input
    onChange={this.saveFormData('password')}
    type="password" id="password" name="password"/><br/>
    <button>登入</button>
  2. 將原本的函數改成柯里化函數

    1
    2
    3
    4
    5
    6
    7
    saveFormData = (dataType) => {
    // 利用 return 回傳函數
    return (event) => {
    // 物件內接收變數需用 []
    this.setState({ [dataType] : event.target.value})
    }
    }

    畫面展示

不使用柯里化的優化方法

  1. 將原本的柯里化函數改成普通回調函數

    1
    2
    3
    4
    5
    saveFormData = (dataType, event) => {
    // 嘗試直接取得值
    this.setState({ [dataType] : event.target.value})
    }
    }
  2. onChange回調函數,改成回調箭頭函數

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <label for="username">帳號:</label>

    // 把 onChange 的函數變成回調箭頭函數
    <input
    onChange={(event)=>this.saveFormData('username', event)}
    type="text" id="username" name="username"/><br/>
    <label for="password">密碼:</label>

    // 把 onChange 的函數變成回調箭頭函數
    <input
    onChange={(event)=>this.saveFormData('password', event)}
    type="password" id="password" name="password"/><br/>
    <button>登入</button>

參考資料