簡體   English   中英

單擊提交按鈕后如何重置輸入值?

[英]How to reset input value after clicking submit button?

import React, { useState } from 'react';
import './StockQuotes.css'; 
import { createMuiTheme, withStyles, makeStyles, ThemeProvider } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
import stockData from '../util/stockData';
import { useDispatch } from 'react-redux';
import { getStocksOwned } from '../slices/stocksOwnedSlice';

const StockQuotes = () => {

    const [sharesToBuy, setSharesToBuy] = useState(stockData);
    const dispatch = useDispatch();
    
    const handleChange = (event, index) => {
        stockData[index].owned = parseInt(event.target.value);
        setSharesToBuy(stockData);
    }
    
    const handleClick = (event, index) => {
        event.preventDefault();
        dispatch(getStocksOwned(sharesToBuy));
        stockData[index].owned = 0;
    }

    const StyledTableCell = withStyles((theme) => ({
        head: {
            backgroundColor: theme.palette.common.black,
            color: theme.palette.common.white,
        },
        body: {
            fontSize: 14,
        },
    }))(TableCell);

    const StyledTableRow = withStyles((theme) => ({
        root: {
            '&:nth-of-type(odd)': {
            backgroundColor: theme.palette.action.hover,
            },
        },
    }))(TableRow);

    const useStyles = makeStyles((theme) => ({
        margin: {
            margin: theme.spacing(1),
        },
        table: {
            minWidth: 700,
            },
    }));

    const classes = useStyles();

    const theme = createMuiTheme({
            palette: {
                primary: {main: '#00e676'},
            },
        });

    return(
        <TableContainer component={Paper}>
            <Table className={classes.table} aria-label="customized table">
                <TableHead>
                    <TableRow>
                        <StyledTableCell>Stock Name</StyledTableCell>
                        <StyledTableCell align="right">Current Price</StyledTableCell>
                        <StyledTableCell align="right">Shares</StyledTableCell>
                        <StyledTableCell align="right">Order</StyledTableCell>
                    </TableRow>
                </TableHead>
                <TableBody>
                {stockData.map((stock, index) => (
                    <StyledTableRow key = {index} >
                        <StyledTableCell component="th" scope="row">
                            {stock.name}
                        </StyledTableCell>
                        <StyledTableCell align="right">${stock.price}</StyledTableCell>
                        <StyledTableCell align="right"><input type="number" onChange={event => handleChange(event, index)}></input></StyledTableCell>
                        <StyledTableCell align="right">
                            <ThemeProvider theme={theme}>
                                <Button variant="contained" color="primary" className={classes.margin} onClick={event => handleClick(event, index)}>
                                    BUY
                                </Button>
                            </ThemeProvider>
                        </StyledTableCell>
                    </StyledTableRow>
                    ))}
                </TableBody>
            </Table>
        </TableContainer>
    )
}

export default StockQuotes;

單擊提交按鈕后,我試圖將 stockData[index].owned 設置為 0。 通常是直截了當的,但這次通過映射包含 8 個對象的 stockData json 文件創建了 8 個輸入字段。 因此,如果我按輸入標簽放置 value 屬性然后鍵入,則整個 8 個輸入字段都會更改。 所以我以這種方式編碼,除非我點擊后,我得到“TypeError:無法分配給對象‘#’的只讀屬性‘擁有’”。 我能做什么?

這里發生了一些事情:

  1. stockData似乎只是用於設置組件狀態的初始值。 初始化狀態后,更新並從sharesToBuy讀取,以便這些更改流向您的組件樹。
  2. 不要改變對象/狀態。 這可能會導致錯誤並阻止您的組件正確更新。 相反,創建一個具有更新值的新副本。
  3. 控制您的input並根據狀態更改更新value
// Convenience function for updating state.
const updateOwnedValue = (index, owned) => {
  // Instead of mutating the array/object, create a copy with the updated values
  // and then update state so the changes flow down to your components.
  const newState = sharesToBuy.map((stock, idx) => (
    idx === index ? { ...stock, owned } : stock
  ));

  setSharesToBuy(newState);
};

const handleChange = (event, index) => {
  updateOwnedValue(index, parseInt(event.target.value));
}

const handleClick = (event, index) => {
  event.preventDefault();
  dispatch(getStocksOwned(sharesToBuy));
  updateOwnedValue(index, 0);
}

...
// Iterate over component state instead of the imported value.
{sharesToBuy.map((stock, index) => (
  ...
  <input
    type="number"
    onChange={event => handleChange(event, index)}
    value={
      // This makes your input a controlled component.
      // The value will respond to state changes.
      stock.owned
    }
  />
  ...
))}

清除輸入

為了在點擊提交時重置輸入,您希望輸入成為受控組件 這意味着它從你傳遞一個value prop 而不是將它存儲在本地獲取它的值。 然后,您的提交事件處理程序的任務是將該值設置為 0。

Material UI 支持受控和非受控組件,因此這應該是一個簡單的更改,但由於應用程序中數據的混亂控制而變得復雜。 這個輸入的值來自哪里? 哪個值需要更改才能將其設置為 0?

數據結構

您需要考慮存在哪些數據及其存儲位置。 來自你的 json 文件的數據應該被使用一次來填充你的應用程序的 initialState 或者它的 redux store ,就是這樣

現在您實際上正在改變從 json 文件導入的stockData值。 這真是糟糕的設計。

您可以將一些信息存儲在 redux 中,將一些信息存儲在本地組件狀態中,但不應在兩個地方使用相同的數據。 本地狀態將用於本地更改,例如在點擊“購買”按鈕之前在表單中輸入的數字。 而每只股票的當前價格應該存儲在 redux 中並通過useSelector訪問。

本次修訂並不完美,但希望它能讓您走上正軌。

嵌套組件

在我上面鏈接的演示中,您可能會注意到輸入組件在您鍵入字符時失去焦點。 發生這種情況的原因是您已經在StockQuotes組件中定義了StyledTableCellStyledTableRow組件。 這意味着每次狀態更改時都會重新創建這些組件。 輸入不被視為相同的輸入,因為它所在的表格單元格是不同的表格單元格,這就是它失去焦點的原因。

您希望將樣式化組件定義為StockQuotes組件之外的頂級組件。 (我嘗試只是將它們復制並粘貼到外面,但這引入了其他錯誤。作為臨時黑客解決方案,您可以使用useMemo來避免重新創建,但這並不理想。)

在 handleClick 函數中,最后重置您的setSharesToBuy

就像,setSharesToBuy('');

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM