【问题标题】:How to reset input value after clicking submit button?单击提交按钮后如何重置输入值?
【发布时间】:2020-10-12 16:55:17
【问题描述】:
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:无法分配给对象'#'的只读属性'拥有'”。我能做什么?

【问题讨论】:

    标签: javascript reactjs redux react-redux


    【解决方案1】:

    这里发生了一些事情:

    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
        }
      />
      ...
    ))}
    
    

    【讨论】:

    • 在输入字段中输入数字的那一刻,我收到此错误“sharesToBuy.map 不是函数”,但“拥有”的对象值在 shareToBuy 状态下正确更新。我只需要解决为什么我一输入单个数字就会收到该错误消息。
    • 哎呀,你是对的。我创建了sharesToBuy 一个对象,但我现在意识到它应该是一个数组。将更新我的答案。
    【解决方案2】:

    在handleClick函数中,最后重置你的setSharesToBuy

    同样,setSharesToBuy('');

    【讨论】:

      【解决方案3】:

      清除输入

      为了在点击提交时重置输入,您希望输入为controlled component。这意味着它的价值是通过你传递一个value 属性而不是在本地存储的。然后,您的提交事件处理程序的任务是将该值设置为 0。

      Material UI 支持受控和不受控的组件,因此这应该是一个简单的更改,但由于应用中数据的混乱控制,它变得复杂了。这个输入的值来自哪里?需要更改哪个值才能将其设置为 0?

      数据结构

      您需要考虑存在哪些数据以及存储在何处。来自您的 json 文件的数据应该使用一次来填充您的应用程序或其 redux 存储的初始状态就是这样

      现在您实际上正在改变从 json 文件导入的 stockData 值。这真是糟糕的设计。

      你可以有一些存储在 redux 中的信息和一些存储在本地组件状态中的信息,但在这两个地方它不应该是相同的数据。本地状态将用于本地更改,例如在点击“购买”按钮之前在表单中输入的数字。而每只股票的当前价格应存储在 redux 中并通过useSelector 访问。

      This Revision 并不完美,但希望它能让您走上正轨。

      嵌套组件

      在我上面链接的演示中,您可能会注意到输入组件在您键入字符时失去焦点。发生这种情况的原因是您在 StockQuotes 组件内定义了组件 StyledTableCellStyledTableRow。这意味着每次状态更改时都会重新创建这些组件。输入不会被视为相同的输入,因为它所在的表格单元格是不同的表格单元格,这就是它失去焦点的原因。

      您希望将样式化组件定义为StockQuotes 组件之外的顶级组件。 (我尝试将它们复制并粘贴到外面,但这会引入其他错误。作为临时黑客解决方案,您可以useMemo 以避免重新创建,但这并不理想。)

      【讨论】:

      • 对于嵌套组件,我明白你的意思。就像你说的那样,我尝试在 StockQuote 组件上方调出 shareToBuy.map 表格部分,然后我得到一堆材料 ui,无法识别他们的表格组件错误。但你引导我走向正确的方向。谢谢!
      猜你喜欢
      • 2021-09-29
      • 2021-09-10
      • 1970-01-01
      • 2012-08-07
      • 2022-10-20
      • 2017-08-15
      • 1970-01-01
      • 2014-12-29
      • 1970-01-01
      相关资源
      最近更新 更多