Home > Back-end >  List of user images feched from API in React are displayed and all 10 images flash to each user imag
List of user images feched from API in React are displayed and all 10 images flash to each user imag

Time:01-10

I am developing a Top10UserList Component in React that fetches the top 10 users from the api, then fetches the image for each of those users and creates an image tag for each user sucessfully, and is supposed to display each user's image in their own tag.

Unfortunately though, every one of the images shares the same state, so they all flash quickly through all 10 images and then stay on the final image.

I need them to be seperate and but I am not sure how I can refactor my code to achieve this.

React Component:

const TOP_USERS_URL = 'http://localhost:8080/users/top-players'
const TOP_TEN_USERS_URL = 'http://localhost:8080/users/top-10-players'
const TOP_TEN_USERS_IMAGES_URL = 'http://localhost:8080/image-files/download-using-username'
const USER_IMG_URL = 'http://localhost:8080/image-files/'
class TopUserList extends Component {

    constructor(props) {
        super(props);
        this.state = { users: [], top10Users: [], token: '', top10UsersImages: [], profUrl: '', profileImage: '' };
    }

    componentDidMount() {
        fetch(TOP_USERS_URL, {
            method: 'GET',
            headers: {
                "Accept": "application/json",
                "Content-Type": "application/json",
                "Authorization": localStorage.getItem("token")
            },
        })
            .then(response => response.json())
            .then(data => this.setState({ users: data }));

        fetch(TOP_TEN_USERS_URL, {
            method: 'GET',
            headers: {
                "Accept": "application/json",
                "Content-Type": "application/json",
                "Authorization": localStorage.getItem("token")
            },
        })
            .then(response => response.json())
            .then(data => {
                this.setState({ top10Users: data });

                console.log(data);
                console.log("Data[0]")
                console.log(data[0].username)

                data.forEach(element => {

                        const imgUrl = USER_IMG_URL   element.username;
                        const id = element.id;

                        fetch(imgUrl, {
                            method: 'GET',
                            headers: {
                                "Authorization": localStorage.getItem("token")
                            }
                        })
                            .then(r => r.arrayBuffer())
                            .then(buffer => {
                                const blob = new Blob([buffer]);
                                this.state.img = URL.createObjectURL(blob);
                            });

                        const fetchImage = async (url) => {
                            try {
                                const response = await fetch(url, {
                                    headers: {
                                        "Authorization": localStorage.getItem("token")
                                    }
                                });
                                const imageBytes = await response.arrayBuffer();
                                var blob = new Blob([imageBytes], { type: "image/jpeg" });
                                var imageUrl = URL.createObjectURL(blob);
                                return imageUrl;
                            } catch (error) {
                                console.log("ERROR:", error);
                            }
                        };

                        const profileUrl = "profile-image-"   id;

                        this.state.profUrl = profileUrl;

                        (async () => {
                            const imageSrc = await fetchImage(imgUrl);
                            console.log("ImageSRC:");
                            console.log(imageSrc);
                            console.log("Profile Url:");
                            console.log(profileUrl);
                            this.setState({ profileImage: imageSrc })
                        })();
                        console.log("Profile Url:");
                        console.log(profileUrl);

                        document.getElementById("app").innerHTML = `
<image id={profileUrl}>

`;
                    }
                );
            });
    }



    render() {
        const { users, top10Users, isLoading, profileUrl, profileImage} = this.state;
        console.log("Top 10 users data: ")
        console.log(top10Users);
        console.log("Top 10 users using index: ");
        console.log(top10Users[0]);
        console.log("ProfUrl: ");
        console.log(profileUrl);
        console.log("profImg");
        console.log(profileImage);

        if (isLoading) {
            return <p>Loading...</p>;
        }

        const topUserList = users.map(user => {
            return <tr key={user.id}>
                <td style={{ whiteSpace: 'nowrap' }} >{user.name}</td>
                <td >{user.username}</td>
                <td >{user.location}</td>
            </tr>
        });

        const topTenUserList = top10Users.map(user => {
            return <div className="user-container" key={user.id}>
                <Card>
                    <div id="app"></div>
                    <img src={profileImage} style={{ width: 200, height: 200 }} />
                    <CardTitle>{user.name}</CardTitle>
                </Card>
            </div>
        })

        return (
            <div className="outer-div-container">
                <div>
                    <Container fluid>
                        <h3 className="player-list-header">Top Players</h3>

                        <Table className="mt-4">
                            <thead>
                            <tr id="player-list-row">
                                <th className="player-list-data-text">Name</th>
                                <th className="player-list-data-text">Username</th>
                                <th className="player-list-data-text">Location</th>
                            </tr>
                            </thead>
                            <tbody>
                            {topUserList}
                            </tbody>
                        </Table>

                        {topTenUserList}
                    </Container>
                </div>
            </div>
        );
    }
}
export default TopUserList;

And the result:

enter image description here

How can I do this in React? Do I need to create 10 different image state values?

Thanks for any help!

Updated code:

class TopUserList extends Component {

    constructor(props) {
        super(props);
        this.state = { users: [], top10Users: [], token: '', top10UsersImages: [], profUrl: '', profileImage: {} };
    }

    componentDidMount() {
        fetch(TOP_USERS_URL, {
            method: 'GET',
            headers: {
                "Accept": "application/json",
                "Content-Type": "application/json",
                "Authorization": localStorage.getItem("token")
            },
        })
            .then(response => response.json())
            .then(data => this.setState({ users: data }));

        fetch(TOP_TEN_USERS_URL, {
            method: 'GET',
            headers: {
                "Accept": "application/json",
                "Content-Type": "application/json",
                "Authorization": localStorage.getItem("token")
            },
        })
            .then(response => response.json())
            .then(data => {
                this.setState({ top10Users: data });

                console.log(data);
                console.log("Data[0]")
                console.log(data[0].username)

                const profileImagesData = {}

                data.forEach((element, userIndex) => {

                        const imgUrl = USER_IMG_URL   element.username;
                        const id = userIndex;

                        fetch(imgUrl, {
                            method: 'GET',
                            headers: {
                                "Authorization": localStorage.getItem("token")
                            }
                        })
                            .then(r => r.arrayBuffer())
                            .then(buffer => {
                                const blob = new Blob([buffer]);
                                this.state.img = URL.createObjectURL(blob);
                            });

                        const fetchImage = async (url) => {
                            try {
                                const response = await fetch(url, {
                                    headers: {
                                        "Authorization": localStorage.getItem("token")
                                    }
                                });
                                const imageBytes = await response.arrayBuffer();
                                var blob = new Blob([imageBytes], { type: "image/jpeg" });
                                var imageUrl = URL.createObjectURL(blob);
                                profileImageData[element?.id] = imageSrc
                                return imageUrl;
                            } catch (error) {
                                console.log("ERROR:", error);
                            }
                        };

                        const profileUrl = "profile-image-"   id;

                        this.state.profUrl = profileUrl;

                        (async () => {
                            const imageSrc = await fetchImage(imgUrl);
                            console.log("ImageSRC:");
                            console.log(imageSrc);
                            console.log("Profile Url:");
                            console.log(profileUrl);

                            this.setState({profileImage:{...profileImageData}})
                            
                            })();
                        console.log("Profile Url:");
                        console.log(profileUrl);

                        document.getElementById("app").innerHTML = `
<image id={profileUrl}>

`;
                    }
                );
            });
    }



    render() {
        const { users, top10Users, isLoading, profileUrl, profileImage} = this.state;
        console.log("Top 10 users data: ")
        console.log(top10Users);
        console.log("Top 10 users using index: ");
        console.log(top10Users[0]);
        console.log("ProfUrl: ");
        console.log(profileUrl);
        console.log("profImg");
        console.log(profileImage);

        if (isLoading) {
            return <p>Loading...</p>;
        }

        const topUserList = users.map(user => {
            return <tr key={user.id}>
                <td style={{ whiteSpace: 'nowrap' }} >{user.name}</td>
                <td >{user.username}</td>
                <td >{user.location}</td>
            </tr>
        });

        const topTenUserList = top10Users.map(user => {
            return <div className="user-container" key={user.id}>
                <Card>
                    <div id="app"></div>
                    <img src={this.state.profileImage[user.id]} style={{ width: 200, height: 200 }} />
                    <CardTitle>{user.name}</CardTitle>
                </Card>
            </div>
        })

        return (
            <div className="outer-div-container">
                <div>
                    <Container fluid>
                        <h3 className="player-list-header">Top Players</h3>

                        <Table className="mt-4">
                            <thead>
                            <tr id="player-list-row">
                                <th className="player-list-data-text">Name</th>
                                <th className="player-list-data-text">Username</th>
                                <th className="player-list-data-text">Location</th>
                            </tr>
                            </thead>
                            <tbody>
                            {topUserList}
                            </tbody>
                        </Table>

                        {topTenUserList}
                    </Container>
                </div>
            </div>
        );
    }
}
export default TopUserList;

CodePudding user response:

You can achieve that by converting your profileImage state from a string value to an object where key of this object will be your user id and the value would be image url

In your code, you may need to make following changes

  1. Your state variable profileImage:'' inside constructor should be replaced by profileImage:{}

  2. In componentDidMount Initialise a variable const profileImageData = {} above this line data.forEach(element

  3. Under const imageSrc = await fetchImage(imgUrl);, once you have the response, do profileImageData[element?.id] = imageSrc (I am assuming that you have an id variable on each of your top10User array)

  4. Replace this.setState({ profileImage: imageSrc }) with this.setState({profileImage:{...profileImageData})

  5. Inside your top10UserList, replace <img src={profileImage} style={{ width: 200, height: 200 }} /> with <img src={this.state.profileImage[user.id]} style={{ width: 200, height: 200 }} />

    If you do not have an id value then you can replace data.forEach(element with data.forEach((element, userIndex) and use userIndex as your key value instead of element.id and do the same in top10UserList as well

  •  Tags:  
  • Related