![](/img/trans.png)
[英]React JS - How to prevent rendering before state being updated [Hooks]
[英]State being updated before execution in react hooks
我正在研究一個使用 HOC 接受輸入(來自用戶的多個圖像和文本)的表單。 下面是我的表單組件。
import React from "react";
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import Alert from "@material-ui/lab/Alert";
import TextField from "@material-ui/core/TextField";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import { Snackbar, IconButton } from "@material-ui/core";
import { Loading, Snackbars, UIButton, UITextField } from "../UI/index";
import {
Paper,
makeStyles,
Button,
} from "@material-ui/core";
function Gallery(props) {
let {
submitHandler,
selectImages,
message,
galleryForm,
inputChangedHandler,
} = props;
return (
<div>
<Paper
elevation={3}
style={{ padding: "20px" }}
>
<form
onSubmit={submitHandler}
noValidate
id="galleryForm"
>
<Grid container spacing={3}>
<Grid item xs={12} md={6}>
<UITextField
name="imageTitle"
label="Image Title"
value={galleryForm.imageTitle.value}
onChange={(event) => inputChangedHandler(event, "imageTitle")}
error={galleryForm.imageTitle.invalid}
helperText={galleryForm.imageTitle.helperText}
/>
</Grid>
<Grid item xs={12} sm={6}>
<Grid container>
<Grid>
<TextField
id="standard-basic"
fullWidth
label="Select File To Upload"
value={message}
error={galleryForm.images.invalid}
helperText={galleryForm.images.helperText}
/>
</Grid>
<Grid>
<input
accept=".jpg , .png, .jpeg"
className={classes.input}
style={{ display: "none" }}
id="raised-file"
multiple
type="file"
onChange={selectImages}
/>
<label htmlFor="raised-file">
<Button
variant="contained"
style={{
background: "#D3D3D3",
color: "black",
fontSize: "15px",
borderRedius: "4px",
}}
component="span"
>
UPLOAD PHOTOS
</Button>
</label>
</Grid>
</Grid>
</Grid>
<Grid className={classes.center}>
<UIButton
type="submit"
variant="contained"
color="primary"
size="large"
className={classes.submit}
>
create gallery
</UIButton>
</Grid>
</Grid>
</form>
</Paper>
</div>
);
}
export default enhancer(Gallery);
下面是我的 HOC(增強器),它采用 Gallery 組件
import React, { useEffect, useState } from "react";
import { compose } from "redux";
import Gallery from "./index";
import galleryFiled from "./galleryField";
export let enhancer = compose((Gallery) => ({ ...props }) => {
const [galleryForm, setGalleryForm] = useState(galleryFiled);
const [message, setMessage] = useState("");
const selectImages = (event) => {
const updatedForm = {
...galleryForm,
};
console.log("check:", galleryForm);
for (var i = 0; i < event.target.files.length; i++) {
if (event.target.files.item(i).name.match(/\.(jpg|jpeg|png)$/)) {
updatedForm.images.value.push(event.target.files.item(i));
}
}
setGalleryForm({ ...updatedForm });
let message = `${updatedForm.images.value.length} valid image(s) selected`;
console.log(galleryForm);
setMessage(message);
};
const inputChangedHandler = (event, inputIdentifier) => {
const updatedForm = {
...galleryForm,
};
console.log(updatedForm);
updatedForm[inputIdentifier].value = event.target.value;
updatedForm[inputIdentifier].invalid = false;
updatedForm[inputIdentifier].helperText = "";
console.log(updatedForm);
setGalleryForm({
...updatedForm,
});
console.log(galleryForm);
};
const clearForm = (event) => {
let allFormKeys = Object.keys(galleryForm);
let formData = { ...galleryForm };
allFormKeys.forEach((formKey) => {
if (formKey == "images") {
formData[formKey].value = [];
formData[formKey].invalid = false;
formData[formKey].helperText = "";
} else {
formData[formKey].value = "";
formData[formKey].invalid = false;
formData[formKey].helperText = "";
}
});
setMessage("");
setGalleryForm(formData);
};
const submitHandler = (event) => {
event.preventDefault();
console.log("submit", galleryForm);
let updatedForm = { ...galleryForm };
console.log("update", updatedForm);
console.log("final form", galleryForm);
clearForm();
};
return (
<Gallery
{...props}
{...{
submitHandler,
selectImages,
message,
galleryForm,
inputChangedHandler,
}}
/>
);
});
export default enhancer;
因此,每當我首先單擊上傳圖像按鈕時,我都會使用galleryForm 的臨時副本,然后在使用selectImage 按鈕function 中的useState 掛鈎將正確的文件更新到galleryForm 之后。
所以我的問題是,當我最初從其打印更新的 galleryForm 打印一個臨時副本時,即使我在 function 的后期階段更新我的表單。
我在 submitHandle function、clearForm function 上也面臨同樣的問題,即使我正在調用 function,也會更新galleryForm,因為我丟失了galleryForm 並且最初由於我丟失了galleryForm 並且最初在最后打印表單數據而變得空了。
您正在使用 spreadSyntax 來克隆您的 galleryForm,但是您必須注意,擴展語法僅制作 object 的淺表副本。 新 object 中的嵌套值仍然共享引用,當您嘗試更新嵌套值時,原始 state 中的值也會反映出來
更新的正確方法是在每個嵌套級別克隆值,如下所示
const selectImages = (event) => {
console.log("check:", galleryForm);
const imagesValue = [];
for (var i = 0; i < event.target.files.length; i++) {
if (event.target.files.item(i).name.match(/\.(jpg|jpeg|png)$/)) {
imagesValue.push(event.target.files.item(i));
}
}
// Update nested state
setGalleryForm(prevGalleryForm => ({
...prevGalleryForm,
images: {
...prevGalleryForm.images,
value: prevGalleryForm.images.concat(imagesValue)
}
}));
let message = `${imagesValue.length} valid image(s) selected`;
console.log(galleryForm);
setMessage(message);
};
const inputChangedHandler = (event, inputIdentifier) => {
const updatedForm = {
...galleryForm,
[inputIdentifier]: {
...galleryForm[inputIdentifier],
value: event.target.value,
invalid: false,
helperText:"",
}
};
console.log(updatedForm);
setGalleryForm(updatedForm);
console.log(galleryForm);
};
const clearForm = (event) => {
let allFormKeys = Object.keys(galleryForm);
let formData = { ...galleryForm };
allFormKeys.forEach((formKey) => {
if (formKey == "images") {
formData[formKey].value = [];
formData[formKey].invalid = false;
formData[formKey].helperText = "";
} else {
formData[formKey].value = "";
formData[formKey].invalid = false;
formData[formKey].helperText = "";
}
});
setMessage("");
setGalleryForm(formData);
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.