Reputation: 1112
I have a parent component and a child component.
The Parent component uploads a new image to an API. The child component displays a list of images returned from the same API.
The problem I am facing is that the child component is always one update behind. That is uploading a single image to the parent component does not refresh it but updating a second image does. Adding a third image will display the previous two images but not the third and so on.
Parent Component
function MediaLibrary(props) {
const [imageUploaded, setImageUploaded] = useState('');
const imagesGateway = ImagesGateway();
const handleUploadImage = async (event) => {
event.preventDefault();
let formdata = new FormData();
formdata.append("image", event.target.files[0]);
await imagesGateway.postArticleImages(props.articleId, formdata);
// Update Files uploaded to try to trigger a refresh
setImageUploaded(Math.random);
}
return (
<Container className="pt-4">
<MediaList articleId={props.articleId} refresh={imageUploaded} />
<Form.File
id="articleImage"
label="Upload Image"
custom
onChange={handleUploadImage}
/>
</Container>
)
export default MediaLibrary;
Child Component
function MediaList(props) {
const [images, setImages] = useState([]);
const [loading, setLoading] = useState(true);
const imageGateway = ImageGateway();
useEffect(() => {
fetchImages();
}, [props]);
const fetchImages = async () => {
setLoading(true);
const articleImages = await imageGateway.getArticleImages(props.articleId);
setImages(articleImages);
setLoading(false);
}
return (
<Container>
<Row>
{images.map(image => (
<Image src={image} thumbnail />
))}
</Row>
</Container>
)
}
export default MediaList;
Edit: It looks like the fetchimages
function in the child component is hit every single time with the correct data from the API but this is not triggering the child component to display the fresh data.
Upvotes: 1
Views: 225
Reputation: 1053
Update your child component as below to let your component properly be affected by your refresh prop changes:
function MediaList({ articleId, refresh }) {
const [images, setImages] = useState([]);
const [loading, setLoading] = useState(true);
const imageGateway = ImageGateway();
useEffect(() => {
fetchImages();
}, [refresh]);
const fetchImages = async () => {
setLoading(true);
const articleImages = await imageGateway.getArticleImages(articleId);
setImages(articleImages);
setLoading(false);
}
return (
<Container>
<Row>
{images.map(image => (
<Image src={image} thumbnail />
))}
</Row>
</Container>
)
}
export default MediaList;
Upvotes: 0
Reputation: 978
Have you try to approach like this:
Parent Component
import React, { useState } from "react";
import MediaList from "./MediaList";
export default function App() {
const [loading, setLoading] = useState(false);
const [images, setImages] = useState([]);
const imagesGateway = ImagesGateway();
const handleUploadImage = async (event) => {
event.preventDefault();
let formdata = new FormData();
formdata.append("image", event.target.files[0]);
await imagesGateway.postArticleImages(props.articleId, formdata);
// Call fetchImages() everytime when you post something new
fetchImages();
};
const fetchImages = async () => {
setLoading(true);
const articleImages = await imageGateway.getArticleImages(props.articleId);
setImages(articleImages);
setLoading(false);
};
return (
<Container className="pt-4">
<MediaList images={images} />
<Form.File
id="articleImage"
label="Upload Image"
custom
onChange={handleUploadImage}
/>
</Container>
);
}
Child Component
import React from "react";
function MediaList(props) {
// Gettings images from props
const { images } = props;
return (
<ul>
{images.map((image) => (
<li>
{image.title}
<img src={image} alt="img" />
</li>
))}
</ul>
);
}
export default MediaList;
Upvotes: 2