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:无法分配为只读对象“#”的属性“拥有””。我该怎么办?
答案 0 :(得分:1)
这里发生了几件事:
stockData
似乎只是用于设置组件状态的初始值。状态初始化后,请进行更新并从sharesToBuy
中读取,以便这些更改流到您的组件树中。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
}
/>
...
))}
答案 1 :(得分:0)
为了在单击“提交”时重置输入,您希望输入为controlled component。这意味着从您传递value
道具而不是将其存储在本地就可以得到它的价值。然后,您的Submit事件处理程序将该值设置为0。
材料UI支持受控和不受控制的组件,因此这应该是一个容易的更改,但是由于您的应用程序中数据的混乱控制使它变得复杂。此输入值从何而来?要将其设置为0,需要更改哪个值?
您需要考虑存在哪些数据以及将其存储在何处。来自json文件的数据应仅用于填充应用程序或其redux存储就是这个的initialState。
现在,您实际上正在突变从json文件导入的stockData
值。这真的是一个糟糕的设计。
您可以将某些信息存储在redux中,将某些信息存储在本地组件状态中,但是这两个地方的数据不应相同。本地状态将用于本地更改,例如在点击“购买”按钮之前在表格中输入的数字。而每只股票的当前价格应存储在redux中,并可以通过useSelector
访问。
This Revision并不完美,但希望它能使您走上正确的轨道。
在我上面链接的演示中,您可能会注意到输入字符时输入组件失去了焦点。发生这种情况的原因是,您已在StyledTableCell
组件内部定义了组件StyledTableRow
和StockQuotes
。这意味着,每次状态更改时,将重新创建这些组件。该输入不被视为相同的输入,因为它所在的表格单元格是不同的表格单元格,这就是为什么它失去焦点的原因。
您想将样式化的组件定义为StockQuotes
组件之外的顶级组件。 (我只是尝试将它们复制并粘贴到外部,但这引入了其他错误。作为一种临时破解解决方案,您可以useMemo
避免重新创建,但这并不理想。)
答案 2 :(得分:0)
在handleClick函数中,最后重置您的setSharesToBuy
就像setSharesToBuy('');