Event handling

在PHP(或傳統的web)裡,是透用Form以及http post,在submit後,送出Form裡的欄位內容給伺服器。在javascript裡,可以利用document.getElementById取得DOM的內容,再利用http post將資料送到伺服器。未來,在介紹FAST API(或Firebase)時,我們會介紹如何將資料送到伺服器。

在react裡,並不建議直接去取得DOM的內容,所以,寫法就跟javascript不一樣了。在react裡,則是在輸入時(onChange)就將內容放到state裡,並將value設為state。(詳參:Responding to Events)

Input (text、number)

我們在productList.tsx,新增一個元件包含兩個輸入框:

  function ProductAdd(){

    return (
      <Box>
      產品描述:<input type="text" name="desc" value={desc} onChange={handleClickDesc}/><br/>
      產品價格:<input type="number" name="price" value={price} onChange={handleClickPrice}/><br/>
      </Box>
    )
  }  

在ProductList裡,加上ProductAdd。

    <Container maxWidth="sm">
    <Box>
      <List subheader="Product list" aria-label="product list">
        {products.map((product, index) =>
          <ListItemButton 
            selected={selectedIndex === index}
            onClick={(event) => handleListItemClick(event, index)}
            divider key={product.desc}>
            <ListItemText primary={product.desc} secondary={product.price}>
            </ListItemText>
          </ListItemButton>)}
      </List>
    </Box>
    **<ProductAdd/>**
    </Container>
    

e是onChange預設傳給被呼叫方法的第一個參數,可以改為任何的變數名稱。可以利用console.log(e.target),就可以看到是取得DOM的元件,再從e.target中取得value,將value放到state裡,注意,因為是onChange,所以,每進行一次內容更動 (輸入一個字)就會觸發call back function(如:handleClickDesc)。

<aside> ⚠️

注意,以下內容要放在ProductAdd哩,否則,當我們輸入內容時,會因為ProductList及ProductAdd一直被重新產生,而導致輸入時一直要重新點輸入框才能繼續輸入。

</aside>

  const [desc, setDesc] = useState("");
  const [price, setPrice] = useState(0);

<aside> 📢 因為price是數字,要記得利用Number()將輸入內容轉成數字。

</aside>

  function handleClickDesc(e) {
    setDesc(e.target.value);
  }
  function handleClickPrice(e) {
    setPrice(Number(e.target.value));
  }

因為我們使用typescript,所以要定義e的資料型態:

  function handleClickDesc(e: React.ChangeEvent<HTMLInputElement>) {
    setDesc(e.target.value);
  }
  function handleClickPrice(e: React.ChangeEvent<HTMLInputElement>) {
    setPrice(Number(e.target.value));
  }

利用useState(),管理desc及price。

<aside> 📢 如果不用useState(),在畫面上就看不到輸入的內容。因為輸入框的值綁訂了desc及price。

</aside>

image.png

接下來,加個按鈕,在點擊按鈕時,就可以呼叫update函數,將輸入內容加到產品清單陣列中。