以下是我的组件,它触发操作并监视更改:
import { Box, Button, Stack, TextField, Typography } from "@mui/material";
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { v4 as uuidv4 } from "uuid";
import {
handleDirectorAdd,
handleDirectorInfoFormChange,
handleDirectorRemove,
} from "../../../../redux/slices/directorInfo";
const DirectorsInformation = () => {
const dispatch = useDispatch();
const directorsInfo = useSelector((state) => state.directorInfo);
const handleChange = (e, index) => {
const { name, value } = e.target;
if (name && value) {
dispatch(handleDirectorInfoFormChange({ name, value, index }));
}
};
const handleAdd = () => {
dispatch(handleDirectorAdd());
};
const handleRemove = (e, index) => {
dispatch(handleDirectorRemove({ index }));
};
return (
<form
onSubmit={handleSubmit}
noValidate
style={{
padding: "1rem",
backgroundColor: "white",
border: "1px solid darkgrey",
textAlign: "center",
}}
>
<Typography variant="body1">
<strong>Director's Information</strong>
</Typography>
<hr />
{directorsInfo?.map((directorInfo, index) => (
<div key={uuidv4()}>
<Stack
spacing={1}
alignItems="center"
style={{
padding: "1rem",
backgroundColor: "rgb(227, 227, 227)",
}}
>
<Typography variant="body1">Director's Information</Typography>
<Button
variant="contained"
color="error"
sx={{ textTransform: "none" }}
onClick={(e) => handleRemove(e, index)}
>
Remove
</Button>
<Typography variant="body1">
<strong>Full Name</strong>
</Typography>
<TextField
fullWidth
size="small"
label="Full Name"
name="name"
value={directorInfo.name}
onChange={(e) => handleChange(e, index)}
sx={{ backgroundColor: "white" }}
/>
<Typography variant="body1">
<strong>Official Email</strong>
</Typography>
<TextField
fullWidth
size="small"
label="Official Email"
name="email"
type="email"
value={directorInfo.email}
onChange={(e) => handleChange(e, index)}
sx={{ backgroundColor: "white" }}
/>
<Typography variant="body1">
<strong>Contact Number</strong>
</Typography>
<TextField
fullWidth
size="small"
label="Contact Number"
name="contactNumber"
value={directorInfo.contactNumber}
onChange={(e) => handleChange(e, index)}
sx={{ backgroundColor: "white" }}
/>
<Typography variant="body1">
<strong>Title</strong>
</Typography>
<TextField
fullWidth
size="small"
label="Tile"
name="title"
type="string"
value={directorInfo.title}
onChange={(e) => handleChange(e, index)}
sx={{ backgroundColor: "white" }}
/>
</Stack>
<Button
variant="contained"
color="success"
sx={{ textTransform: "none", margin: "2rem 0" }}
onClick={handleAdd}
>
Add Directors Information
</Button>
</div>
))}
</form>
);
};
export default DirectorsInformation;
现减速机及动作如下:
import { createSlice, current } from "@reduxjs/toolkit";
const initialValues = {
name: "",
email: "",
contactNumber: "",
username: "",
title: "",
};
const initialState = [initialValues];
const directorInfo = createSlice({
name: "directorInfo",
initialState,
reducers: {
handleDirectorAdd(state, action) {
return [...state, initialValues];
},
handleDirectorRemove(state, action) {
return state.filter((_, index) => index !== action.payload.index);
},
handleDirectorInfoFormChange(state, action) {
const { index, name, value } = action.payload;
return state.map((director, idx) => {
if (idx === index) {
return {
...director,
[name]: value,
};
} else {
return director;
}
});
},
},
});
export const {
handleDirectorAdd,
handleDirectorRemove,
handleDirectorInfoFormChange,
} = directorInfo.actions;
export default directorInfo.reducer;
我面临的问题是,当我更改表单输入字段中的值时,该值会更新,但会导致重新渲染(我假设因为输入字段的焦点已被删除)。当任何控制器的值发生更改或添加和删除它们时,我试图更新 redux 存储中的状态。任何帮助将非常感激。
谢谢你
我试图改变状态。状态正在正确改变,但它导致重新渲染,这是我不想要的。我尝试过过滤功能而不是地图,但仍然无法达到预期的结果。我希望用户能够顺利地在输入框内书写
当您更新状态时,重新渲染将是预期的结果。您遇到的根本问题是由于在映射的
directorsInfo
状态数组上的每个渲染周期使用随机 React 键引起的。
{directorsInfo?.map((directorInfo, index) => (
<div key={uuidv4()}> // <-- Random React key == bad
...
</div>
))}
每次
DirectorsInformation
重新渲染时,每个映射的 directorsInfo
数组元素的 JSX 都使用一个 不同 React 键(与上一个渲染周期相比),因此 React 将此 JSX 视为新的并卸载旧的JSX 并安装新的 JSX 即使它是相同的 UI。
解决方案在这种情况下,我建议向您的州添加一个
id
属性。如果您愿意,可以继续使用
uuid
包,但 Redux-Toolkit 还可以针对此类用例重新导出
nanoid
。
示例:
import { createSlice, nanoid } from "@reduxjs/toolkit";
const initialValues = {
name: "",
email: "",
contactNumber: "",
username: "",
title: "",
};
const initialState = [{
...initialValues,
id: nanoid(), // <-- generate id when creating object
}];
const directorInfo = createSlice({
name: "directorInfo",
initialState,
reducers: {
handleDirectorAdd(state, action) {
state.push({
...initialValues,
id: nanoid(), // <-- generate id when creating object
});
},
handleDirectorRemove(state, action) {
return state.filter((director) => director.id !== action.payload.id);
},
handleDirectorInfoFormChange(state, action) {
const { id, name, value } = action.payload;
return state.map((director) => director.id === id
? { ...director, [name]: value }
: director);
},
},
});
const DirectorsInformation = () => {
const dispatch = useDispatch();
const directorsInfo = useSelector((state) => state.directorInfo);
const handleChange = (e, id) => {
const { name, value } = e.target;
if (name && value) {
dispatch(handleDirectorInfoFormChange({ name, value, id }));
}
};
const handleAdd = () => {
dispatch(handleDirectorAdd());
};
const handleRemove = (e, id) => {
dispatch(handleDirectorRemove({ id }));
};
return (
<form
onSubmit={handleSubmit}
noValidate
style={{
padding: "1rem",
backgroundColor: "white",
border: "1px solid darkgrey",
textAlign: "center",
}}
>
<Typography variant="body1">
<strong>Director's Information</strong>
</Typography>
<hr />
{directorsInfo?.map((director) => (
<div key={director.id}> // <-- use id property
<Stack
spacing={1}
alignItems="center"
style={{
padding: "1rem",
backgroundColor: "rgb(227, 227, 227)",
}}
>
<Typography variant="body1">Director's Information</Typography>
<Button
variant="contained"
color="error"
sx={{ textTransform: "none" }}
onClick={(e) => handleRemove(e, director.id)} // <-- pass id property
>
Remove
</Button>
<Typography variant="body1">
<strong>Full Name</strong>
</Typography>
<TextField
fullWidth
size="small"
label="Full Name"
name="name"
value={director.name}
onChange={(e) => handleChange(e, director.id)} // <-- pass id property
sx={{ backgroundColor: "white" }}
/>
<Typography variant="body1">
<strong>Official Email</strong>
</Typography>
<TextField
fullWidth
size="small"
label="Official Email"
name="email"
type="email"
value={director.email}
onChange={(e) => handleChange(e, director.id)} // <-- pass id property
sx={{ backgroundColor: "white" }}
/>
<Typography variant="body1">
<strong>Contact Number</strong>
</Typography>
<TextField
fullWidth
size="small"
label="Contact Number"
name="contactNumber"
value={director.contactNumber}
onChange={(e) => handleChange(e, director.id)} // <-- pass id property
sx={{ backgroundColor: "white" }}
/>
<Typography variant="body1">
<strong>Title</strong>
</Typography>
<TextField
fullWidth
size="small"
label="Tile"
name="title"
type="string"
value={director.title}
onChange={(e) => handleChange(e, director.id)} // <-- pass id property
sx={{ backgroundColor: "white" }}
/>
</Stack>
<Button
variant="contained"
color="success"
sx={{ textTransform: "none", margin: "2rem 0" }}
onClick={handleAdd}
>
Add Directors Information
</Button>
</div>
))}
</form>
);
};