---
# System prepended metadata

title: React - 高階函數柯里化
tags: [React]

---

---
title: React - 高階函數柯里化
tags: React
date: 2021/8/9
---

###### tags: `React`

###### *date: 2021/8/9*

# ⚛️ React - 高階函數柯里化

[TOC]

## 什麼是高階函數?

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

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

常見的高階函數：`Promise`、`setTimeout`、`array.map`...

## 函數柯里化

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

## 還沒優化受控組件的 `onChange`

以受控組件表單為例

- 有多少個輸入框，就有多少個方法
- 每個方法都是做重複的一件事情，把值存入狀態裡

```jsx
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`方法，將功能相同，參數不同的方法變成一個
    - 首先理解綁定事件的回調函數
        - 回調函數不加`()`是把函數做為回調函數
        - 回調函數若加`(參數)`則是把**返回值**做為回調

    ```jsx
    <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. 將原本的函數改成柯里化函數

    ```jsx
    saveFormData = (dataType) => {
        // 利用 return 回傳函數
        return (event) => {
          // 物件內接收變數需用 []
          this.setState({ [dataType] : event.target.value})
        }
    }
    ```

    ![control](https://i.imgur.com/ReVfD2Q.png)

## 不使用柯里化的優化方法

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

    ```jsx
    saveFormData = (dataType, event) => {
          // 嘗試直接取得值
          this.setState({ [dataType] : event.target.value})
        }
    }
    ```

2. 將`onChange`回調函數，改成回調箭頭函數

    ```jsx
    <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>
    ```

### 參考資料

- [React 官網 - 高階組件](https://zh-hant.reactjs.org/docs/higher-order-components.html)
- [React 全家桶](https://www.youtube.com/playlist?list=PLmOn9nNkQxJFJXLvkNsGsoCUxJLqyLGxu)
