React: How can I show an already existing image in react update form and then show the new one once a new image is uploaded?

Tags: , , , ,



hey guys i am learning react js and I have an update form to update book info. I am using django rest api for endpoints. I have a working form where I can upload files and do all those stuffs but I am not able to show the image which is already there in the template, Here I have a book cover image, which is already there in the database, it should be showing in the front-end and when I change the image, the new one should show, how can I add that feature here, I tried <img src={formData.book_cover} and consoling out this is showing the url, but the image isn’t getting displayed.

From the network tab, The problem I think is

Request URL:http://localhost:3000/media/book/book_sample/pride_in_nat.png

request url since the image gets displayed if the url is localhost:8000 instead of localhost:3000 as it is where the django server backend runs. So, how can I change that?

This is the code.

import React from "react";

function BookInfoForm() {

  const initialFormData = Object.freeze({
  id: '',
  book_cover: '',
  book_name: '',
  book_summary: '',
});

const [formData, updateFormData] = useState(initialFormData);
const [image, setImage] = useState(null);
const { register, handleSubmit, control, errors } = useForm();

useEffect(() => {
  axiosInstance.get('api/books/info/update/').then((res) => {
    updateFormData({
              ...formData,
      ['book_cover']: res.data.book_cover,
      ['book_name']: res.data.book_name,
      ['book_summary']: res.data.book_summary,
    });
  });
  }, [updateFormData]);

  const handleChange = (e) => {
    if (e.target.name === 'image') {
        setImage({
            image: e.target.files,
        });
        // console.log(e.target.files);
    } 
    updateFormData({
        ...formData,         
  // Trimming any whitespace
      [e.target.name]: e.target.value
    });
};

const onSubmit = (data) =>{
  let formData = new FormData();

  formData.append('user', user.id),
  formData.append('book_cover', data.image[0]),
  formData.append('book_name', data.book_name),
  formData.append('book_summary', data.book_summary),

  axiosInstance.put('api/books/info/update/', formData),
}

return (
  <>
    <form className={classes.form} noValidate onSubmit={handleSubmit(onSubmit)}>
      <Grid container spacing={2}>
            <Grid item xs={6}>
                {/* Show existing book cover and change when new one is uploaded */}
                <img src={formData.store_logo} alt="" />
                <label htmlFor="book-cover">
                    <input
                    accept="image/*"
                    className={classes.input}
                    id="book-cover"
                    onChange={handleChange}
                    name="image"
                    type="file"
                    ref={register}
                />
                    Book Cover
                    <IconButton color="primary" component="span">
                        <PhotoCamera />
                    </IconButton>
                </label>
            </Grid>

            <Grid item xs={12}>
                <TextField
                    variant="outlined"
                    required
                    fullWidth
                    id="book_name"
                    label="Book Name"
                    name="book_name"
                    autoComplete="book_name"
                    value={formData.book_name}
                    onChange={handleChange}
                    inputRef={register({maxLength: 30})}
                    rows={1}
                />
            </Grid>

            <Grid item xs={12}>
                <TextField
                    variant="outlined"
                    required
                    fullWidth
                    id="book_summary"
                    label="Book Summary"
                    name="book_summary"
                    autoComplete="book_summary"
                    value={formData.book_summary}
                    onChange={handleChange}
                    inputRef={register({maxLength: 1000})}
                    multiline
                    rows={3}
                />
            </Grid>
          </Grid>

          <Button
            type="submit"
            fullWidth
            variant="contained"
            color="primary"
            className={classes.submit}
          >
            Update
        </Button>

      </form>
  </>
)
}

Answer

You might want to take a look at one of my answers on Why React needs webpack-dev-server to run?

As your frontend is running at localhost:3000 and you are providing a relative path to the img tag, the browser is assuming that the image is at localhost:3000.

Whenever your backend host is different than the frontend host, you have to provide a complete URL to the resource i.e., origin(http://localhost:8000) + path to the resource(/book/book_sample/pride_in_nat.png)

As you are storing the path to the resource in your database, just append the origin while giving it to the img tag.

<img src={`http://localhost:8000/${formData.store_logo}`} />

Suggestion

A better approach is to use .env files and load them according to your development or production environment

<img src={`${process.env.IMAGE_STORE_ORIGIN}${formData.store_logo}`} />

And in your .env file or .env.development file, you can add the entry for where your images are stored

In your .env file:

IMAGE_STORE_ORIGIN=http://localhost:8000/

So, when you want to change your backend server origin, you can just change it in one location and it is used inside your entire app instead of changing it manually every time you want to use a new server address.

Take a look at dotenv and dotenv-expand

I hope this should clarify your “why” and “what”.



Source: stackoverflow