我有一个表单,它从父组件获取用户数据作为
prop
进行更新,更新它们然后设置父组件的状态,但是当 userData
状态更改时父组件不会重新渲染,因此我必须刷新页面查看更新
父组件
useEffect(() => {
const getUsers = async () => {
const res = await fetch("http://localhost:8000/api/users", {
credentials: "include",
});
const data = await res.json();
if (data.status === 401) {
dispatch({ type: "LOGOUT" });
navigate("/login");
}
setUsers(data.users);
// setUsers(data.users.filter((u) => u.id != 80));
};
getUsers();
}, [dispatch, navigate, user?.id]);
let emptyUser = {
id: "",
firstName: "",
lastName: "",
position: "",
gender: "",
birthDate: "",
status: "",
isAdmin: "",
image: null,
url: "",
};
const [userData, setUserData] = useState(emptyUser);
const editUser = (user) => {
setUserData(user);
};
子组件
function UpdateUser({ userData, editditUser }) {
const onSelectFile = (e) => {
if (!e.target.files || e.target.files.length === 0) {
editUser({ ...userData, image: undefined });
return;
}
editUser({ ...userData, image: e.target.files[0] });
setDisableBtn(false);
};
const onInputChange = (e, variable) => {
const val = (e.target && e.target.value) || "";
let _user = { ...userData };
_user[`${variable}`] = val;
editUser(_user);
setDisableBtn(false);
};
const editUser = async (e) => {
e.preventDefault();
let errors = {};
if (
userData.firstName.length > 15 ||
userData.lastName.length > 15 ||
userData.firstName.length < 3 ||
userData.lastName.length < 3
) {
errors.errName =
"First name and/or must be between 3 and 15 characters in length.";
}
if (!userData.gender) {
errors.errGender = "Gender must not be empty.";
}
if (!userData.status) {
errors.errStatus = "Status must not be empty.";
}
setErrors(errors);
if (Object.keys(errors).length > 0) {
return;
}
setDisableBtn(true);
let url;
if (preview) {
const imageRef = storageRef(storage, `images/${Date.now()}`);
const snapshot = await uploadBytes(imageRef, userData.image);
url = await getDownloadURL(snapshot.ref);
}
const userToUpdate = {
firstName: userData.firstName,
lastName: userData.lastName,
email: userData.email,
position: userData.position,
gender: userData.gender,
birthDate: userData.birthDate,
image: url || userData.image,
status: userData.status,
isAdmin: userData.isAdmin === "Admin" ? 1 : 0,
};
const res = await fetch(
`http://localhost:8000/api/edit-user/${userData.id}`,
{
credentials: "include",
method: "PUT",
body: JSON.stringify(userToUpdate),
headers: { "Content-Type": "application/json" },
}
);
const data = await res.json();
if (data.status === 401) {
dispatch({ type: "LOGOUT" });
navigate("/login");
}
if (data.status === 400) {
setDisableBtn(false);
setErrUser(data.message);
return false;
}
console.log("success");
};
}
IIUC,父组件获取用户列表(从后端),并保持
userData
状态以在需要时编辑这些用户之一。此 userData
状态与子组件共享,子组件显示编辑表单并处理对后端的请求,以在提交表单时保存更新的用户数据。
但是父级中的列表并不反映该用户的更改,因为显示的数据不是已修改的状态。
在这种情况下,您可以通过多种方式显示更新后的用户,具体取决于您的 Parent JSX 的结构以及它如何调用 Child。
鉴于您共享的代码,解决方案之一可能是在更新请求成功后重新获取整个用户列表。额外的优点是您一定会检索后端实际存储的内容(它可能会清理/拒绝某些更新):
// PARENT
// Build the fetch function separately, so that it can be called imperatively
// once the update request succeeds
const getUsers = useCallback(async () => {
const res = await fetch("http://localhost:8000/api/users", {
credentials: "include",
});
const data = await res.json();
if (data.status === 401) {
dispatch({ type: "LOGOUT" });
navigate("/login");
}
setUsers(data.users);
}, [dispatch, navigate]);
// Fetch users list initially
useEffect(() => {
getUsers();
}, []);
return <UpdateUser
onUpdateSuccess={getUsers} // Pass the fetch function as callback
// Other props
/>;
// CHILD (UpdateUser)
function UpdateUser({
onUpdateSuccess,
// Other props
}) {
const editUser = async (e) => {
// Prepare data, send request to Backend...
console.log("success");
// Fire the callback
onUpdateSuccess?.();
};
}