Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.3k views
in Technique[技术] by (71.8m points)

reactjs - how to update old avatar image once new image uploaded without refresh

I don't know if I need to use global state like useContext for this ( I am not using redux in this project) but what I want to do is, once I have uploaded a new image it sends the image data back from the server and I set that state. I want to then replace the existing image on the screen with the newly uploaded one.

So, here is my file input component:

import React, { useState } from "react";
import ProgressBar from "../../../shared/components/progressBar/ProgressBar";

const UploadForm = () => {
  const [file, setFile] = useState(null);
  const [error, setError] = useState(null);

  const types = ["image/png", "image/jpg", "image/jpeg"];

  const changeHandler = (e) => {
    let selected = e.target.files[0];

    if (selected && types.includes(selected.type)) {
      setFile(selected);
      setError("");
    } else {
      setFile(null);
      setError("Please select an image file(png or jpg");
    }
  };
  return (
    <form>
      <input type="file" onChange={changeHandler} name="image"></input>
      <div className="output">
        {error && <div className="error">{error}</div>}
        {file && <div>{file.name}</div>}
        {file && <ProgressBar file={file} setFile={setFile} />}
      </div>
    </form>
  );
};

export default UploadForm;

My progress bar component:

import React, { useEffect } from "react";
import useStorage from "../../hooks/use-storage";
import { motion } from "framer-motion";
import "./ProgressBar.css";

const ProgressBar = ({ file, setFile }) => {
  const { url, progress } = useStorage(file);

  useEffect(() => {
    if (url) {
      setFile(null);
    }
  }, [url, setFile]);

  return (
    <motion.div
      className="upload-progress"
      initial={{ width: 0 }}
      animate={{ width: progress + "%" }}
    ></motion.div>
  );
};

export default ProgressBar;

And, my upload custom hook. You can see here I am setting the state of the image url here but I don't know how to then update my Avatar component once the upload is complete.

import React, { useState, useEffect, useContext } from "react";
import Axios from "axios";
import { AuthContext } from "../context/auth-context";

const useStorage = (file) => {
  const auth = useContext(AuthContext);
  const [progress, setProgress] = useState(0);
  const [error, setError] = useState(null);
  const [url, setUrl] = useState(null);

  useEffect(() => {
    const formData = new FormData();
    formData.append("image", file);

    try {
      const sendImage = async () => {
        const response = await Axios.post(
          "http://localhost:8000/api/v1/users/update-avatar",
          formData,
          {
            headers: {
              "Content-type": "multipart/form-data",
              Authorization: "Bearer " + auth.token,
            },
            onUploadProgress: (progressEvent) => {
              setProgress(
                parseInt(
                  Math.round((progressEvent.loaded * 100) / progressEvent.total)
                )
              );
            },
          }
        );
        // get the new file name from the server so you can show it right away after upload

        const { filename, path } = response.data.file;
        setUrl({ filename, path });
      };

      sendImage();
    } catch (err) {
      setError(err);
      console.log(err.response);
    }
  }, [file]);

  return { progress, url, error };
};

export default useStorage;

Avatar component

import React, { useContext, useEffect, useState } from "react";
import Axios from "axios";
import { AuthContext } from "../../../shared/context/auth-context";

const Avatar = () => {
  const auth = useContext(AuthContext);
  const [avatar, setAvatar] = useState(null);
  useEffect(() => {
    const getAvatarImage = async () => {
      const response = await Axios.get(
        "http://localhost:8000/api/v1/users/get-avatar",
        { headers: { Authorization: "Bearer " + auth.token } }
      );
      setAvatar(response.data.avatar);
    };
    if (auth.token) getAvatarImage();
  }, [auth.token]);

  return (
    <div>
      {avatar && (
        <img
          src={`http://localhost:8000/uploads/images/${avatar}`}
          width="200"
          alt="avatar image"
        />
      )}
    </div>
  );
};

export default Avatar;

Auth Context

import { createContext } from "react";

export const AuthContext = createContext({
  isLoggedIn: false,
  userId: null,
  token: null,
  email: null,
  firstName: null,
  login: () => {},
  logout: () => {},
});

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
等待大神解答

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...