iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 14
1
Modern Web

從比入門再往前一點開始,一直到深入React.js系列 第 14

【Day.14】React入門 - 輸入元素與控制組件

React 在輸入元素的處理上有一些比較特別的地方,先前我們已經使用過onClick(),這篇我們來一次講全部輸入元素。

事件處理

onClick

之前都用過。總之輸入事件都是用原生DOM API傳入的event去處理。event.target是被點擊的對象,event.target.value則是被點擊的對象的value。

<button value={123} onClick={(event)=>{ console.log(event.target.value)} } ></button>

onChange - input/text、textarea、select

每當輸入值一被改變,就會呼叫onChange裡的函式,剩下都跟onClick一樣。

<select onChange={(e)=>{console.log(e.target.value)}}>
        <option value="123">123</option>
        <option value="456">456</option>
</select>

onSubmit - form

 <form onSubmit={handleSubmit}>
      <input type="submit" value="Submit" />
 </form>

初始值

在過去,我們如果要給輸入元素初始值,要用value。但在React的輸入元素中value有別的用途,那我們要怎麼給初始值呢?

defaultValue

初始值改成了用defaultValue這個屬性。你可以用下面這個範例來測試:

import React,{useState} from "react";

const InputForm=()=>{
    const [word,setWord]=useState("初始文字");
    return (
        <>
            <input 
                type="text" 
                defaultValue={word} 
                onChange={(e)=>{setWord(e.target.value)}}
            />
            <div>word的值:{word}</div>
        </>
    )
}
export default InputForm;

用state綁定輸入元素 - 控制組件

那麼value被改成了什麼呢? 答案是「input中目前的值」。舉例來說,如果你照剛剛一樣給defaultValue,然後用<input/>來設定word這個state:

import React,{useState} from "react";

const InputForm=()=>{
    const [word,setWord]=useState("初始文字");
    return (
        <>
            <button onClick={(e)=>{setWord("")}}>清除word</button>
            <input 
                type="text" 
                defaultValue={word} 
                onChange={(e)=>{setWord(e.target.value)}}
            />
            <div>word的值:{word}</div>
        </>
    )
}
export default InputForm;

你會發現當你按下第一個按鍵時,input中的值並沒有跟隨著word而改變,這是因為defaultValue只和第一次渲染元素時有關。接著我們改把word綁在value上:

import React,{useState} from "react";

const InputForm=()=>{
    const [word,setWord]=useState("初始文字");
    return (
        <>
            <button onClick={(e)=>{setWord("")}}></button>
            <input 
                type="text" 
                value={word} 
                onChange={(e)=>{setWord(e.target.value)}}
            />
            <div>word的值:{word}</div>
        </>
    )
}
export default InputForm;

此時input中的值就會始終跟隨著word。這樣用state綁定輸入元素的方式我們稱為控制組件。

當你想用Http Request取得的值去設定input初始值時,你應該要使用value而不是defaultValue。因為非同步特性,第一次渲染時你幾乎不可能拿到Http Request的Response,所以defaultValue就不可能變成Response data。

關閉輸入元素 - disabled

請注意因為當我們只寫名稱、不給props值時,React會預設認定該props為true,所以以下兩者是一樣的:

<input type="text" disabled />
<input type="text" disabled={true} />

selected - option

select元素的初始選取選項可以透過<option>上的selected來控制

<select onChange={(e)=>{setSelect(e.target.value)}}>
    <option value="123">123</option>
    <option selected={true} value="456" >456</option>
</select>

checked - input/radio

核取和選取的input都是用check這個props來控制是否被選取

const [check,setCheck]=useState(false);
<input type="radio" checked={check} value="123" onChange={(e)=>{setCheck(true)}} />123<br/>
<input type="radio" checked={!check} value="456" onChange={(e)=>{setCheck(false)}} />456

一次處理很多輸入元素的事件

當今天輸入的元素很多, 就可能變成元件中有一大堆的setState。這樣不僅可讀性差,如果想要一次處理一堆輸入元素也很麻煩。

除了第三方插件外,React官方推薦的做法是給每個元素name屬性。把所有元素綁定單一函式,並在函式中以event.target.name來分流處理。

你會發現官方文件中class component的state是統一用this.setState設定,所以可以用computed property name語法。但funtion component不行。

你可能會寫出類似這樣的架構:

import React from "react";

const handleMulInput=(e)=>{
    if (e.target.name === "account"){
        console.log("account is "+e.target.value);
    } else if (e.target.name === "password"){
        console.log("password is "+e.target.value);
    }
}

const InputForm=()=>{
    return (
        <div>
            <input 
                type="text" 
                name="account" 
                onChange={handleMulInput}
            />
            <input 
                type="text" 
                name="password"
                onChange={handleMulInput}
            />
        </div>
    )
}
export default InputForm;

但這樣做因為函式定義在非React function component內,這樣就不能使用React hook了。

那我們要把函式直接定義在function component內嗎? 怎麼樣取得元素內的值會比較好呢?

在接下來的這幾天,我們會依序提到React處理非控制組件的api、以及React效能處理的討論。到時候再回來談要如何處理這個case。


上一篇
【Day.13】React入門 - useEffect(生命週期)
下一篇
【Day.15】React入門 - 非控制組件與useRef
系列文
從比入門再往前一點開始,一直到深入React.js30

1 則留言

0
yanzhong
iT邦新手 4 級 ‧ 2021-01-08 00:37:27

很有用的系列!!!

我要留言

立即登入留言