【问题标题】:update real time in react and nodejs [duplicate]在反应和nodejs中实时更新[重复]
【发布时间】:2021-03-29 23:57:51
【问题描述】:

我正在尝试实现当用户在网站上上传他们的个人资料图片时,它会自动将旧的个人资料图片更改为新的个人资料图片,而不是用户必须注销并重新登录才能使其正常工作。

这是我的前端代码库:

const UserCard = ({ picture, name, userEmail, isVerified, id, setPicture, setUser}) => {

      const [imageSelected, setImageSelected] = useState("");
    
      useEffect(() => {
        if (imageSelected !== '') {
          uploadImage();
        }
         
      }, [imageSelected]);
    
    
      const uploadImage = () => {
        const formData = new FormData();
        formData.append("file", imageSelected);
        formData.append("id", id);
    
        axios
          .post("/api/v1/users/upload/image", formData, {
            headers: { "Content-Type": "multipart/form-data" },
          })
          .then((response) => {
            setPicture(response.data.data.imageUrl);
            setUser(prev => ({ ...prev, picture: response.data.data.imageUrl }));

          });
      };
      // End of Method
      const inputFile = useRef(null);
      const onButtonClick = () => {
        // `current` points to the mounted file input element
       inputFile.current.click();
      };
    
      return (
        <div className="avatar--icon_profile">
          <Card className="profile--card_container">
            <CardContent>
              {picture ? (
                <div>
                  <input
                    className="my_file"
                    type="file"
                    ref={inputFile}
                    onChange={(e) => setImageSelected(e.target.files[0])}
                  />
                    <div className="profile-image">                
                      <Avatar
                          src={picture}
                          alt="Avatar"
                          className="avatar--profile_image"
                          onClick={onButtonClick}
                      />
                      </div>
                 </div>
             </div>

这是我的后端路由器,用于将图像从客户端发送到云端(我存储所有图像):

router.post('/upload/image', function (req, res, next) {

  const dUri = new Datauri();

  const dataUri = (req) => dUri.format(path.extname(req.name).toString(), req.data);

  if (req.files !== undefined && req.files !== null) {
    const { file, id } = req.files;

    const newFile = dataUri(file).content;
   
    cloudinary.uploader.upload(newFile)
      .then(result => {
        const imageUrl = result.url;
        const data = {id : req.body.id, imageUrl };
      updateAvatar(data);
      return res.status(200).json({ message: 'Success', data: { imageUrl } });
    }).catch(err =>  res.status(400).json({message:'Error', data: { err}}));
  } else {
    return res.status(400).json({ message: 'Error' });
  }

});

我怎样才能实现它?

添加了 GlobalState.js:

const GlobalState = (props) => {
  // User State -----------------------------------------------------------------------------
  const [currentUser, setUser] = useState(props.serverUserData);

  // This method is passed through context to update currentUser
  const updateUser = (userData) => {
    setUser(userData);
  };

  // Modal State -----------------------------------------------------------------------------
  const [isModalOpen, setModalOpenState] = useState(false);
  const [modalToDisplay, setModalToDisplay] = useState("signup");

  // This function will be provided to any function that needs to toggle the modal.
  const toggleModal = () => {
    // Take the previous state and flip it.
    setModalOpenState((prevState) => !prevState);
  };

  // This method is passed through context to update the next modal to open.
  const setModal = (name) => {
    // Take the passed in modal name and set state.
    setModalToDisplay(name);
  };

  // Loading State ---------------------------------------------------------------------------
  // NOT REACT STATE
  const [loading, setLoadingState] = useState(false);

  // This state will be used as messages in effects to refetch data.
  const [reloadThisData, setWhatToReload] = useState("");

  // User profile id for query ----------------------------------------------------------------
  const [userProfileId, setUserProfileId] = useState("");

  // Flag to determine if the header should change css style.  ----------------------------------------------------------------
  const [adjustBrightness, setAdjustBrightness] = useState(false);

  // This is the object passed to GlobalContext.Provider
  const providerValues = {
    isModalOpen,
    toggleModal,
    modalToDisplay,
    setModal,
    currentUser,
    updateUser,
    loading,
    setLoadingState,
    reloadThisData,
    setWhatToReload,
    userProfileId,
    setUserProfileId,
    adjustBrightness,
    setAdjustBrightness,
  };
  
  return (
    <GlobalContext.Provider value={providerValues}>
      {props.children}
    </GlobalContext.Provider>
  );
};

export default GlobalState;

添加了 console.log(currentUser):

{id: "a9aa869e-e28b-4a06-b5c7-88571d490e04", name: "nhan nguyen", email: "nhannguyen4119@gmail.com", publicId: "nh1615539696370", picture: "http://res.cloudinary.com/teammateme/image/upload/v1617073225/hvckrm6bklbpjk9njrlf.jpg", …}
email: "nhannguyen4119@gmail.com"
id: "a9aa869e-e28b-4a06-b5c7-88571d490e04"
isSessionValid: true
name: "nhan nguyen"
picture: "http://res.cloudinary.com/teammateme/image/upload/v1617073225/hvckrm6bklbpjk9njrlf.jpg"
publicId: "nh1615539696370"
__proto__: Object

编辑后更新我的代码:

const UserProfile = () => {
  const appState = useContext(GlobalContext);
  const { currentUser, setUser } = appState;
  const { email, name, id } = currentUser;
  const [isVerified, setIsVerified] = useState(false);

  const [picture, setPicture] = useState(currentUser.picture);

  const checkVerificationData = () => {
    axios.get("/api/v1/profiles/profile").then((res) => {
      const { data } = res;   
      if (data.verifiedDT) {
        setIsVerified(data.verifiedDT);
      }
    });
  };

  useEffect(() => {
    checkVerificationData();
  }, [isVerified]);


  const classes = useStyles();
  return (
    <div className={classes.root}>
      <Grid item xs={12}
        container
        direction="row"
        justify="center"
        alignItems="center"
        spacing={4}>
        <Grid item>
          <Grid item>
            <UserCard
              picture={picture}
              setPicture={setPicture}
              userEmail={email}
              name={name}
              isVerified={isVerified}
              id={id}
              setUser={setUser}
            />
            <br />
          </Grid>
          <div>
            <Grid item>
              <div className="profile--layout_userInfo">
                <Grid item>
                  <UserInfo />
                </Grid>
              </div>
            </Grid>
          </div>
        </Grid>
        <div>
          <Grid item>
            <div className="profile--layout_ratings_reviews_block">
              <UserRatingsDetailed userEmail={email} />
            </div>
          </Grid>
        </div>
      </Grid>
    </div>
  );
};

export async function getServerSideProps(context) {
  let serverUserData = {};

  if (
    context.req.session.passport !== undefined &&
    context.req.session.passport.user !== undefined
  ) {
    const userPassportInfo = context.req.session.passport.user;
    const { id, name, email, publicId, picture } = userPassportInfo;
    const isSessionValid = context.req.isAuthenticated();

    serverUserData = {
      id,
      name,
      email,
      publicId,
      picture,
      isSessionValid,
    };
  }

  return { props: { serverUserData } };
}


UserProfile.propTypes = {
  serverUserData: PropTypes.object, 
};

export default UserProfile;

【问题讨论】:

  • 您提到注销并登录是显示新个人资料图片的方式,而不是简单的页面刷新。这是因为您在登录过程中进行了头像信息的初始拉取吗?
  • @HenryEcker 我不明白你所说的初始拉动是什么意思?
  • 我想我的问题是:您通常如何检索用户的个人资料图片?在uploadImage 函数结束时执行该过程不是一个选项吗?
  • 我通过上下文检索用户信息。我在帖子中添加了我的上下文
  • 那么我的建议是在您的全局上下文管理中添加类似getUserProfileImage 的内容,并在您上传新图像后调用它。或者,由于您似乎正在返回照片的新网址,请添加 updateUserProfileLink 并将新网址传递给该网址。

标签: node.js reactjs next.js


【解决方案1】:

我在回答表单中的 cmets 建议是在你的 react 应用程序的全局上下文中创建一个类似于其他管理器的管理器。

const GlobalState = (props) => {
    // Profile Image -----------------------------------------------------------------------
    const [currentProfileImage, setProfileImage] = useState(/*props.serverUserData.profileImage??*/);
    ...
};

export default GlobalState;

不要忘记更新您的 providerValues 以包含这些新值。

然后,在您使用个人资料图像 URI 的任何地方,都可以使用上下文提供程序中的 currentProfileImage 变量。

最后,当您将图片上传到服务器并在响应中收到新的 URI 时,请使用全局状态中的 setProfileImage 函数来更新全局状态下的个人资料图片。

const uploadImage = () => {
    const formData = new FormData();
    formData.append("file", imageSelected);
    formData.append("id", id);

    axios.post("/api/v1/users/upload/image", formData, {
        headers: {"Content-Type": "multipart/form-data"},
    }).then((response) => {
        GlobalState.setProfileImage(response.data.data.imageUrl);
    });
};

*我对您的程序没有完整的了解,因此这是我对实现所需行为的合理方法的最佳猜测。

您需要更新 useState 指令的初始状态以反映您的 props 结构中 profileImage URI 的实际位置,并且您需要更新 GlobalState 占位符以反映您的情况实际上正在访问您提供的上下文。

【讨论】:

  • 我刚刚在我的帖子中添加了 console.log currentUser 对象。那是我需要放入我的 useState 的对象吗?
  • props.serverUserData.picturecurrentUser.picture 您只是想更新图片 URI。
  • 有了有关 currentUser 结构的新信息,您可能只需使用现有的用户挂钩并使用 currentUser.picturesetUser(prev =&gt; ({...prev, picture:response.data.data.imageUrl}))
  • 我试过了还是不行
  • 我不知道我是否对您的项目的各个部分如何组合在一起有足够清晰的了解以了解问题所在。我也不知道在UserProfileUserCard 级别创建新钩子是否有效。我认为您需要直接从您的上下文中访问它们,例如 appState.setUser({...}appState.currentUser.picture 目前看来您只是保留本地副本而不是直接使用上下文值。
猜你喜欢
  • 2021-07-18
  • 2021-03-18
  • 1970-01-01
  • 2016-01-18
  • 2021-09-17
  • 2021-09-04
  • 2021-09-18
  • 2020-10-30
  • 1970-01-01
相关资源
最近更新 更多