Reactjs 如何在res.data之后设置两个不同的useState

Reactjs 如何在res.data之后设置两个不同的useState,reactjs,Reactjs,我正在制作前端组件,将上传两个不同的图像,封面照片和用户的头像照片。我正在使用node.js作为我的express.js后端。如果用户上传封面照片,后端将发送res.send(如果图像是封面照片或阿凡达照片,它将保护图像路径)。但是我有一个问题,在用户上传图片之后,如何在中同时上传这两个图片。我曾经使用过不同的useState userInfo.coverPhoto和userInfo.avataphoto。问题是,用户单击封面照片后,再单击头像照片,封面照片的图像src将被破坏。但在刷新后,图像

我正在制作前端组件,将上传两个不同的图像,封面照片和用户的头像照片。我正在使用node.js作为我的express.js后端。如果用户上传封面照片,后端将发送res.send(如果图像是封面照片或阿凡达照片,它将保护图像路径)。但是我有一个问题,在用户上传图片之后,如何在中同时上传这两个图片。我曾经使用过不同的useState userInfo.coverPhoto和userInfo.avataphoto。问题是,用户单击封面照片后,再单击头像照片,封面照片的图像src将被破坏。但在刷新后,图像将出现在那里

userProfile.js
    import React, { useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import axios from 'axios';
import PersonIcon from '@material-ui/icons/Person';
import {
  Container,
  Grid,
  Typography,
  TextField,
  Button,
  Modal,
  Backdrop,
} from '@material-ui/core';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import CardMedia from '@material-ui/core/CardMedia';
import ImageIcon from '@material-ui/icons/Image';
import AccountCircleIcon from '@material-ui/icons/AccountCircle';
import { useForm } from 'react-hook-form';
import FormContainer from '../components/FormContainer';
import useStyles from '../styles/style';
import {
  getDetailsUser,
  updateDetailsUser,
} from '../redux/actions/userActions';

const ProfilePage = ({ history }) => {
  const userDetails = useSelector((state) => state.userDetails);
  const { user } = userDetails;

  const userLogin = useSelector((state) => state.userLogin);
  const { userData } = userLogin;

  const userUpdateDetails = useSelector((state) => state.userUpdateDetails);
  const { userUpdate } = userUpdateDetails;

  const [userInfo, setUserInfo] = useState({
    id: user._id,
    username: '',
    email: '',
    fullname: '',
    coverPhoto: '',
    avatarPhoto: '',
    about: '',
    mainAddress: '',
    country: '',
    city: '',
    zipcode: '',
  });
  const [coverPreview, setCoverPreview] = useState('');
  const [avatarPreview, setAvatarPreview] = useState('');
  const [open, setOpen] = useState(false);
  const dispatch = useDispatch();
  const classes = useStyles();

  useEffect(() => {
    if (!userData) {
      history.push('/user/login');
    } else {
      if (!user || !user.username || userUpdate) {
        dispatch(getDetailsUser('profile'));
        // if (!userInfo.coverPhoto) {
        //   document.getElementById(
        //     'coverPhoto-file-button'
        //   ).nextElementSibling.style.opacity = '0';
        // }
      } else {
        setUserInfo(user);
      }
    }
  }, [userData, user, userUpdate, history]);

  const handleClose = () => {
    setOpen(false);
  };

  const handleChange = (level) => (e) => {
    e.preventDefault();
    if (!level) {
      setUserInfo({
        ...userInfo,
        [e.target.name]: e.target.value,
      });
    } else {
      setUserInfo({
        ...userInfo,
        [level]: {
          ...userInfo[level],
          [e.target.name]: e.target.value,
        },
      });
    }
  };

  const uploadCoverPhotoHandler = async (e) => {
    const imgFile = e.target.files[0];
    const imgFieldName = e.target.name;

    if (imgFile.type !== 'image/jpeg' && imgFile.type !== 'image/png') {
      console.log('wrong format');
    }

    let formData = new FormData();
    formData.append(imgFieldName, imgFile);

    try {
      await axios({
        method: 'POST',
        url: 'http://localhost:5000/user/profile',
        data: formData,
        headers: {
          'content-type': 'multipart/form-data',
        },
      }).then((res) => {
        if (imgFieldName === 'coverPhoto') {
          setUserInfo({ coverPhoto: res.data });
        } else {
          setUserInfo({ avatarPhoto: res.data });
        }
      });
    } catch (error) {
      console.log(error.response);
    }
  };

  const onSubmit = async (e) => {
    dispatch(updateDetailsUser(userInfo));
    setOpen(true);
  };

  const { register, handleSubmit, errors, getValues } = useForm({
    mode: 'onSubmit',
    reValidateMode: 'onBlur',
  });

  return (
    <FormContainer>
      <Container component="div" className={classes.profileContainer}>
        <Modal
          className={classes.modal}
          open={open}
          closeAfterTransition
          BackdropComponent={Backdrop}
          BackdropProps={{
            root: classes.modalRoot,
            timeout: 500,
          }}
        >
          <div className={classes.modalContainer}>
            <Typography
              component="h1"
              variant="h5"
              className={classes.promptTitle}
            >
              Account has been updated!
            </Typography>
            <Button
              type="submit"
              variant="contained"
              className={classes.button}
              onClick={handleClose}
              style={{ width: '60%', marginBottom: '2.5rem' }}
            >
              Close
            </Button>
          </div>
        </Modal>
        <Grid item xs={12}>
          <Card className={classes.userProfileCard}>
            <CardContent>
              <form noValidate onSubmit={handleSubmit(onSubmit)}>
                <Typography
                  component="h1"
                  variant="h4"
                  className={classes.titleProfile}
                >
                  <PersonIcon
                    style={{
                      position: 'relative',
                      top: '5px',
                      marginRight: '0.2em',
                    }}
                  />
                  Edit Profile
                </Typography>
                <Grid container spacing={2}>
                  <Grid item xs={6}>
                    <TextField
                      variant="outlined"
                      id="username"
                      name="username"
                      type="text"
                      label="Username"
                      value={userInfo && userInfo.username}
                      onChange={handleChange()}
                      fullWidth
                      InputLabelProps={{
                        classes: {
                          root: classes.label,
                          focused: classes.focused,
                        },
                        shrink: true,
                      }}
                      InputProps={{
                        className: classes.textfield,
                        classes: {
                          root: classes.cssOutlinedInput,
                          focused: classes.cssFocused,
                          notchedOutline: classes.notchedOutline,
                        },
                      }}
                      inputRef={register({
                        required: 'You must provide an username.',
                        minLength: {
                          value: 4,
                          message:
                            'Your username must be greater than 4 characters',
                        },
                        pattern: {
                          value: /^[A-Za-z0-9_]+$/i,
                          message:
                            'Username may only have letters, number and underscores.',
                        },
                      })}
                    />
                    {errors.username && (
                      <span className={classes.error}>
                        {errors.username.message}
                      </span>
                    )}
                  </Grid>
                  <Grid item xs={6}>
                    <TextField
                      variant="outlined"
                      id="email"
                      name="email"
                      type="email"
                      label="Email"
                      value={userInfo && userInfo.email}
                      onChange={handleChange()}
                      fullWidth
                      InputLabelProps={{
                        classes: {
                          root: classes.label,
                          focused: classes.focused,
                        },
                        shrink: true,
                      }}
                      InputProps={{
                        className: classes.textfield,
                        classes: {
                          root: classes.cssOutlinedInput,
                          focused: classes.cssFocused,
                          notchedOutline: classes.notchedOutline,
                        },
                      }}
                      inputRef={register({
                        required: 'You must provide a email.',
                        pattern: {
                          value: /^[^@ ]+@[^@ ]+\.[^@ .]{2,}$/,
                          message: 'You must provide a valid email address!',
                        },
                      })}
                    />
                    {errors.email && (
                      <span className={classes.error}>
                        {errors.email.message}
                      </span>
                    )}
                  </Grid>
                  <Grid item xs={12}>
                    <TextField
                      variant="outlined"
                      id="fullname"
                      name="fullname"
                      type="text"
                      label="Fullname"
                      value={userInfo && userInfo.fullname}
                      onChange={handleChange()}
                      fullWidth
                      InputLabelProps={{
                        classes: {
                          root: classes.label,
                          focused: classes.focused,
                        },
                        shrink: true,
                      }}
                      InputProps={{
                        className: classes.textfield,
                        classes: {
                          root: classes.cssOutlinedInput,
                          focused: classes.cssFocused,
                          notchedOutline: classes.notchedOutline,
                        },
                      }}
                      inputRef={register({
                        required: 'You must provide a fullname.',
                        minLength: {
                          value: 6,
                          message:
                            'Your password must be greater than 6 characters',
                        },
                        pattern: {
                          value: /^[A-Za-z ]+$/i,
                          message: 'Alphabetical characters only',
                        },
                      })}
                    />
                    {errors.fullname && (
                      <span className={classes.error}>
                        {errors.fullname.message}
                      </span>
                    )}
                  </Grid>
                  <Grid item xs={12}>
                    <TextField
                      variant="outlined"
                      id="mainAddress"
                      name="mainAddress"
                      type="text"
                      label="Address"
                      value={userInfo.address && userInfo.address.mainAddress}
                      onChange={handleChange('address')}
                      fullWidth
                      InputLabelProps={{
                        classes: {
                          root: classes.label,
                          focused: classes.focused,
                        },
                        shrink: true,
                      }}
                      InputProps={{
                        className: classes.textfield,
                        classes: {
                          root: classes.cssOutlinedInput,
                          focused: classes.cssFocused,
                          notchedOutline: classes.notchedOutline,
                        },
                      }}
                    />
                  </Grid>
                  <Grid item xs={2}>
                    <TextField
                      variant="outlined"
                      id="city"
                      name="city"
                      type="text"
                      label="City"
                      value={userInfo.address && userInfo.address.city}
                      onChange={handleChange('address')}
                      fullWidth
                      InputLabelProps={{
                        classes: {
                          root: classes.label,
                          focused: classes.focused,
                        },
                        shrink: true,
                      }}
                      InputProps={{
                        className: classes.textfield,
                        classes: {
                          root: classes.cssOutlinedInput,
                          focused: classes.cssFocused,
                          notchedOutline: classes.notchedOutline,
                        },
                      }}
                    />
                  </Grid>
                  <Grid item xs={2}>
                    <TextField
                      variant="outlined"
                      id="country"
                      name="country"
                      type="text"
                      label="Country"
                      value={userInfo.address && userInfo.address.country}
                      onChange={handleChange('address')}
                      fullWidth
                      InputLabelProps={{
                        classes: {
                          root: classes.label,
                          focused: classes.focused,
                        },
                        shrink: true,
                      }}
                      InputProps={{
                        className: classes.textfield,
                        classes: {
                          root: classes.cssOutlinedInput,
                          focused: classes.cssFocused,
                          notchedOutline: classes.notchedOutline,
                        },
                      }}
                    />
                  </Grid>
                  <Grid item xs={2}>
                    <TextField
                      variant="outlined"
                      id="zipcode"
                      name="zipcode"
                      type="text"
                      label="Zipcode"
                      value={userInfo.address && userInfo.address.zipcode}
                      onChange={handleChange('address')}
                      fullWidth
                      InputLabelProps={{
                        shrink: true,
                        classes: {
                          root: classes.label,
                          focused: classes.focused,
                        },
                      }}
                      InputProps={{
                        className: classes.textfield,
                        classes: {
                          root: classes.cssOutlinedInput,
                          focused: classes.cssFocused,
                          notchedOutline: classes.notchedOutline,
                        },
                      }}
                      inputRef={register({
                        pattern: {
                          value: /^[0-9]+([0-9]+)?$/,
                          message: 'Numbers only',
                        },
                      })}
                    />
                    {errors.zipcode && (
                      <span className={classes.error}>
                        {errors.zipcode.message}
                      </span>
                    )}
                  </Grid>
                  <Grid item xs={12}>
                    <Grid item xs={12}>
                      <TextField
                        variant="outlined"
                        id="aboutme"
                        name="about"
                        type="text"
                        label="About me"
                        value={userInfo && userInfo.about}
                        onChange={handleChange()}
                        fullWidth
                        multiline
                        rows={2}
                        InputLabelProps={{
                          classes: {
                            root: classes.label,
                            focused: classes.focused,
                          },
                          shrink: true,
                        }}
                        InputProps={{
                          className: classes.textfield,
                          classes: {
                            root: classes.cssOutlinedInput,
                            focused: classes.cssFocused,
                            notchedOutline: classes.notchedOutline,
                          },
                        }}
                      />
                    </Grid>
                  </Grid>
                  <Grid item xs={2}>
                    <Button
                      type="submit"
                      fullWidth
                      variant="contained"
                      className={classes.button}
                    >
                      Update
                    </Button>
                  </Grid>
                </Grid>
              </form>
            </CardContent>
          </Card>
        </Grid>
        <Grid item xs={12}>
          <Card className={classes.userCard}>
            <form id="userPhoto">
              <CardContent className={classes.coverPhotoContainer}>
                <CardMedia
                  component="img"
                  src={userInfo && userInfo.coverPhoto}
                  height="180rem"
                  onload="this.style.display=''"
                />
                <input
                  accept="image/*"
                  id="coverPhoto-file-button"
                  type="file"
                  name="coverPhoto"
                  style={{ display: 'none' }}
                  onChange={uploadCoverPhotoHandler}
                />
                <label htmlFor="coverPhoto-file-button">
                  <ImageIcon />
                  Add Cover Photo
                </label>
              </CardContent>
              <CardContent className={classes.imgProfileContainer}>
                <CardMedia
                  component="img"
                  src={userInfo && userInfo.avatarPhoto}
                  height="180rem"
                  onload="this.style.display=''"
                />
                <input
                  accept="image/*"
                  id="imgProfile-file-button"
                  type="file"
                  name="avatarPhoto"
                  style={{ display: 'none' }}
                  onChange={uploadCoverPhotoHandler}
                />
                <label htmlFor="imgProfile-file-button">
                  <AccountCircleIcon />
                </label>
              </CardContent>
            </form>
            <CardContent>
              <Typography
                className={classes.titleProfileUsername}
                variant="h6"
                component="h1"
              >
                {userInfo && userInfo.username}
              </Typography>
              <Typography
                className={classes.profileAbout}
                variant="body2"
                component="p"
              ></Typography>
            </CardContent>
          </Card>
        </Grid>
      </Container>
    </FormContainer>
  );
};

export default ProfilePage;
userProfile.js
从“React”导入React,{useState,useffect};
从'react redux'导入{useDispatch,useSelector};
从“axios”导入axios;
从“@material ui/icons/Person”导入PersonIcon;
进口{
集装箱,
网格,
排版,
TextField,
按钮
情态动词
背景
}来自“@material ui/core”;
从“@material ui/core/Card”导入卡片;
从“@material ui/core/CardContent”导入CardContent;
从“@material ui/core/CardMedia”导入CardMedia;
从“@material ui/icons/Image”导入ImageIcon;
从“@material ui/icons/AccountCircle”导入AccountCircleIcon;
从“react hook form”导入{useForm};
从“../components/FormContainer”导入FormContainer;
从“../styles/style”导入useStyles;
进口{
getDetailsUser,
更新的tailsuser,
}来自“../redux/actions/userActions”;
const ProfilePage=({history})=>{
const userDetails=useSelector((state)=>state.userDetails);
const{user}=userDetails;
const userLogin=useSelector((state)=>state.userLogin);
const{userData}=userLogin;
const userUpdateDetails=useSelector((state)=>state.userUpdateDetails);
const{userUpdate}=userUpdateDetails;
const[userInfo,setUserInfo]=useState({
id:user.\u id,
用户名:“”,
电子邮件:“”,
全名:“”,
封面照片:'',
阿凡达照片:'',
关于:'',
主地址:'',
国家:“,
城市:'',
zipcode:“”,
});
const[coverPreview,setCoverPreview]=useState(“”);
const[avatarPreview,setAvatarPreview]=使用状态(“”);
const[open,setOpen]=useState(false);
const dispatch=usedpatch();
const classes=useStyles();
useffect(()=>{
如果(!userData){
history.push('/user/login');
}否则{
如果(!user | |!user.username | | userUpdate){
调度(getDetailsUser(“配置文件”);
//如果(!userInfo.coverPhoto){
//document.getElementById(
//“封面照片文件按钮”
//).nextElementSibling.style.opacity='0';
// }
}否则{
setUserInfo(用户);
}
}
},[userData,user,userUpdate,history]);
常量handleClose=()=>{
setOpen(假);
};
常量句柄更改=(级别)=>(e)=>{
e、 预防默认值();
如果(!级别){
setUserInfo({
…用户信息,
[e.target.name]:e.target.value,
});
}否则{
setUserInfo({
…用户信息,
[级别]:{
…用户信息[级别],
[e.target.name]:e.target.value,
},
});
}
};
const uploadCoverPhotoHandler=异步(e)=>{
const imgFile=e.target.files[0];
常量imgFieldName=e.target.name;
if(imgFile.type!=“image/jpeg”&&imgFile.type!=“image/png”){
console.log(“格式错误”);
}
设formData=new formData();
formData.append(imgFieldName,imgFile);
试一试{
等待axios({
方法:“POST”,
网址:'http://localhost:5000/user/profile',
数据:formData,
标题:{
“内容类型”:“多部分/表单数据”,
},
})。然后((res)=>{
如果(imgFieldName===‘封面照片’){
setUserInfo({coverPhoto:res.data});
}否则{
setUserInfo({avataphoto:res.data});
}
});
}捕获(错误){
console.log(error.response);
}
};
const onSubmit=async(e)=>{
调度(更新的用户信息);
setOpen(真);
};
常量{register,handleSubmit,errors,getValues}=useForm({
模式:“onSubmit”,
重新验证模式:“onBlur”,
});
返回(
帐户已更新!
接近
编辑配置文件
{errors.username&&(
{错误.用户名.消息}
)}
{errors.email&&(
{errors.email.message}
)}
{errors.fullname&&(
{errors.fullname.message}
)}
{errors.zipcode&&(
{errors.zipcode.message}
)}
更新
}).then((res) => {
        if (imgFieldName === 'coverPhoto') {
         setUserInfo(prevState => ({ ...prevState, coverPhoto: res.data }));
        } else {
          setUserInfo(prevState => ({ ...prevState, avatarPhoto: res.data }));
        }
      });