reactjs - 为什么当我更改状态时我的 React 应用程序没有重新渲染?
问题描述
我有一个使用以下模型的 React 应用程序:
export interface DataModel {
itemId: string,
itemName: string,
}
我为模型定义一个初始值,如下所示:
export const INIT_ITEM:DataModel = {
itemId: "",
itemName: "",
}
这在 Dashbaord 组件中使用,该组件显示了一个允许用户设置名称、最小值和最大值的表单。姓名为必填项;minimumValue 和 maximumValue 不是,但如果它们都存在,则 maximumValue 需要大于 minimumValue。此验证在提交表单时完成。这是仪表板组件:
interface ErrorHolder { // Holds error strings
selectedItems: string,
selection1: string,
selection2: string,
valid: boolean
}
const INIT_VALIDATION:ErrorHolder = {
selectedItems: "",
selection1: "",
selection2: "",
valid: false
}
// availableItems is an array of <DataModel>, prepopulated with available options
// selectedItems is an array of <DataModel>, and is initially empty
// selection1 and selection2 are both <DataModel> objects, which are initialised as above
//
// The items from availableItems are displayed with checkboxes. The user must select at least one item to // display on the Dashboard; the list of selected items is stored as selectedItems
// The user must also select an item to be 'selection1' and a different item to be 'selection2'
//
const Dashboard = ( {availableItems, selectedItems, setSelectedItems, selection1, setSelection1, selection2, setSelection2} ) => {
const [valid, setValid] = useState<ErrorHolder>(INIT_VALIDATION); // Initialise error strings
const handleChangeItemSelected = (event:React.ChangeEvent<HTMLInputElement>, checked:boolean) => {
const itemId:number = event.target.value;
if(checked) {
// Checkbox is checked, so this item should be shown
const newSelectedItems = [...selectedItems];
const fullItem = availableItems.filter(item => item.itemId === itemId);
newSelectedItems .push(fullItem[0]);
setSelectedItems(newSelectedItems );
}else {
// Checkbox is not checked, so this item should not be shown
const newSelectedItems = selectedItems.filter(item=> item.itemId !== itemId);
setSelectedItems(newSelectedItems );
}
}
const handleSelectItem = (event: { target: HTMLSelectElement }) => {
let thisItem:DataModel|undefined = undefined;
let selectedId = parseInt(event.target.value);
if(selectedId !== 0) {
const findItem = availableItems.filter(item => item.itemId === selectedId);
thisItem = findItem[0];
}
// Check which item is being changed
switch(event.target.id) {
case 'selection1':
setSelection1(thisItem);
break;
case 'metric2Select':
setSelection2(thisItem);
break;
}
}
const handleSubmit = (event: SyntheticEvent) => {
event.preventDefault();
// Validate
let tempValid:ErrorHolder = INIT_VALIDATION;
tempValid.valid = true;
// Validate everything - set error if found
if(selectedItems.length === 0) { // There must be at least 1 selected item
tempValid.valid = false;
tempValid.selectedItems = "Please select at least one item";
}
// Make sure 2 different items are selected for selection 1 and selection 2
if(!selection1) {
tempValid.valid = false;
tempValid.selection1 = "Please select two items to show on the chart";
}else if(!selection2) {
tempValid.valid = false;
tempValid.selection2 = "Please select two items to show on the chart";
}else if(selection1.itemId === selection2.itemId) {
tempValid.valid = false;
tempValid.selection2= "Please select two different items to show on the chart";
}
}
setValid(tempValid);
}
return (
<form onSubmit = { handleSubmit }>
// List available options
<div>{valid.selectedItems}</div> // Display error message for selected items
<table>
<thead>
<tr>
<td>Name</td>
<td>Show</td>
</tr>
</thead>
<tbody>
{
availableItems.map((item) => { // List all available items with checkboxes
<tr key={item.itemId}>
<td>{item.itemName}</td>
<td><Checkbox value={item.itemId}
onChange={handleChangeItemSelected}
checked={selectedItems.includes(item)} /></td>
</tr>
})
}
</tbody>
</table>
<select id = "selection1" onChange = { event => handleSelectItem(event) }
value = { selection1?.itemId}>
<option key="sel1" value="0">Please Select</option>
{
availableItems.map((item) => <option key={item.itemId} value={item.itemId}>{item.itemName}</option>;
}
</select>
<div>{valid.selection1}</div>
<select id = "selection2" onChange = { event => handleSelectItem(event) }
value = { selection2?.itemId}>
<option key="sel2" value="0">Please Select</option>
{
availableItems.map((item) => <option key={item.itemId} value={item.itemId}>{item.itemName}</option>;
}
</select>
<div>{valid.selection2}</div>
</form>
);
}
export default Dashboard;
我遇到的问题是,如果我输入无效数据(例如,不选择任何内容,为 selection1 和 selection2 等选择相同的内容)并单击“提交”,错误不会显示。如果我做一个控制台日志,我可以看到该valid
变量已正确设置,但似乎该组件没有重新渲染以显示它。
我究竟做错了什么?
解决方案
在每次调用handleSubmit
你时都会改变同一个对象INIT_VALIDATION
,并且将同一个对象传递给setState
函数不会触发重新渲染。
如果您通过替换复制
let tempValid:ErrorHolder = INIT_VALIDATION
和
const tempValid:ErrorHolder = {...INIT_VALIDATION}
我希望它能够工作。(这let
不是问题的一部分,但如果您不更改变量本身,则可以使用 aconst
代替。)
推荐阅读
- c# - Dependency-Inversion-Principal:我应该为接口使用额外的项目/DLL吗?
- c++ - 处理 Eigen::Index 转换警告
- laravel - GET /account: Returns API Token on response
- libgdx - Scene2d 在堆栈上定位组件
- odoo-14 - odoo14 根据条件显示 logo
- amazon-cloudwatch - 您可以将 JSON 文件转换为 CloudWatch Log 吗?
- build - 如何在 Chromium 中构建特定文件
- azure-devops - 无法使用 YAML 参数类型步骤
- time-series - 临时变量的历史数据可以用在响应式状态引擎的定义函数中吗?
- java - java中的对象属性修改