I am using a spring boot backend with a react.js frontend for a web application. Once a user is logged in, it directs the user to their Profile
where they will have their username, profile picture, and a banner displayed on the screen. I have developed a backend service that returns the necessary information in the body of my GET request on Postman such as the link of the image (Profile or Banner). How can I use React to obtain the necessary link in profile_img_complete
and insert it into my image that has a default image in it already if the value is null? My demo user has an image in the database ready to be used, so it should not be displaying the default image, but it is. Any help would be deeply appreciated, here is an image of the information on Postman.
Profile.jsx:
import React, {useState, useEffect} from 'react'; import {Link} from 'react-router-dom'; import {useSelector} from 'react-redux'; import UserProfileService from '../../services/user-profile.service'; import './styles/Profile.css'; const Profile = () => { const {user: currentUser} = useSelector((state) => state.auth); const {id: currentId} = useSelector((state) => state.auth); const [content, setContent] = useState(''); const [photoURL, setPhotoURL] = useState('../../images/user-solid.svg'); //user-solid is the default image I want if the profile image link is null useEffect(() => { UserProfileService.getProfile().then( (response) => { setContent(response.data); }, (error) => { const _content = (error.response && error.response.data && error.response.data.message) || error.message || error.toString(); setContent(_content); } ); if (currentId && currentId.profile_img_complete) { setPhotoURL(currentId.profile_img_complete); } }, [currentId]); if (!currentUser) { return <Link to='/login' />; } return ( <div className='page'> <div className='profile-container'> <header className='jumbotron'> <h3> <strong id='profile-name'>{currentUser.username}</strong> Profile </h3> </header> <p> <img src={photoURL} alt='Avatar' className='avatar'></img> <strong>Token:</strong> {currentUser.accessToken.substring(0, 20)} ...{' '} {currentUser.accessToken.substr(currentUser.accessToken.length - 20)} </p> <p> <strong>Id:</strong> {currentUser.id} </p> <p> <strong>Email:</strong> {currentUser.email} </p> <strong>Authorities:</strong> <ul> {currentUser.roles && currentUser.roles.map((role, index) => <li key={index}>{role}</li>)} </ul> <button> <Link to={'/profile/edit'}>Edit Profile</Link> </button> </div> </div> ); }; export default Profile;
auth.js:
// We’re gonna import AuthService to make asynchronous HTTP requests with trigger one or more dispatch in the result. // – register(): calls the AuthService.register(username, email, password) & dispatch setMessage if successful/failed // – login(): calls the AuthService.login(username, password) & dispatch setMessage if successful/failed // – logout(): calls the AuthService.logout(). // setMessage is imported from message slice that we’ve created above. // We also need to use Redux Toolkit createAsyncThunk which provides a thunk that will take care of the action types and dispatching the right actions based on the returned promise. //There are 3 async Thunks to be exported: // register // login // logout import {createSlice, createAsyncThunk} from '@reduxjs/toolkit'; import {setMessage} from './messages'; import AuthService from '../services/auth.service'; const user = JSON.parse(localStorage.getItem('user')); export const register = createAsyncThunk( 'auth/register', async ({username, email, password}, thunkAPI) => { try { const response = await AuthService.register(username, email, password); thunkAPI.dispatch(setMessage(response.data.message)); return response.data; } catch (error) { const message = (error.response && error.response.data && error.response.data.message) || error.message || error.toString(); thunkAPI.dispatch(setMessage(message)); return thunkAPI.rejectWithValue(); } } ); export const login = createAsyncThunk( 'auth/login', async ({username, password}, thunkAPI) => { try { const data = await AuthService.login(username, password); return {user: data}; } catch (error) { const message = (error.response && error.response.data && error.response.data.message) || error.message || error.toString(); thunkAPI.dispatch(setMessage(message)); return thunkAPI.rejectWithValue(); } } ); export const logout = createAsyncThunk('auth/logout', async () => { await AuthService.logout(); }); const initialState = user ? {isLoggedIn: true, user} : {isLoggedIn: false, user: null}; const authSlice = createSlice({ name: 'auth', initialState, extraReducers: { [register.fulfilled]: (state, action) => { state.isLoggedIn = false; }, [register.rejected]: (state, action) => { state.isLoggedIn = false; }, [login.fulfilled]: (state, action) => { state.isLoggedIn = true; state.user = action.payload.user; }, [login.rejected]: (state, action) => { state.isLoggedIn = false; state.user = null; }, [logout.fulfilled]: (state, action) => { state.isLoggedIn = false; state.user = null; }, }, }); const {reducer} = authSlice; export default reducer;
user-profile.service.js:
import axios from 'axios'; import authHeader from './auth-header'; const API_URL = 'http://localhost:8080/'; const getProfile = () => { return axios.get(API_URL + 'profile', {headers: authHeader()}); }; const user_profile = { getProfile, }; export default user_profile;
Advertisement
Answer
I’m assuming that the data in the image is the value of response.data
that is returned by UserProfileService.getProfile()
. You need to update the photoURL when the UserProfileService.getProfile()
request is fulfilled. Besides, currentId is a string. It does not contain profile_img_complete
attribute.
import React, {useState, useEffect} from 'react'; import {Link} from 'react-router-dom'; import {useSelector} from 'react-redux'; import UserProfileService from '../../services/user-profile.service'; import './styles/Profile.css'; const Profile = () => { const {user: currentUser} = useSelector((state) => state.auth); const {id: currentId} = useSelector((state) => state.auth); const [content, setContent] = useState(''); const [photoURL, setPhotoURL] = useState('../../images/user-solid.svg'); //user-solid is the default image I want if the profile image link is null useEffect(() => { UserProfileService.getProfile().then( (response) => { setContent(response.data); if (response.data.profile_img_complete) setPhotoURL(response.data.profile_img_complete); }, (error) => { const _content = (error.response && error.response.data && error.response.data.message) || error.message || error.toString(); setContent(_content); } ); }, [currentId]); if (!currentUser) { return <Link to='/login' />; } return ( <div className='page'> <div className='profile-container'> <header className='jumbotron'> <h3> <strong id='profile-name'>{currentUser.username}</strong> Profile </h3> </header> <p> <img src={photoURL} alt='Avatar' className='avatar'></img> <strong>Token:</strong> {currentUser.accessToken.substring(0, 20)} ...{' '} {currentUser.accessToken.substr(currentUser.accessToken.length - 20)} </p> <p> <strong>Id:</strong> {currentUser.id} </p> <p> <strong>Email:</strong> {currentUser.email} </p> <strong>Authorities:</strong> <ul> {currentUser.roles && currentUser.roles.map((role, index) => <li key={index}>{role}</li>)} </ul> <button> <Link to={'/profile/edit'}>Edit Profile</Link> </button> </div> </div> ); }; export default Profile;
Alternate Solution
state.auth
should already hold profile_img_complete
. So, you can also do this
import React, {useState, useEffect} from 'react'; import {Link} from 'react-router-dom'; import {useSelector} from 'react-redux'; import UserProfileService from '../../services/user-profile.service'; import './styles/Profile.css'; const Profile = () => { const {user: currentUser} = useSelector((state) => state.auth); const auth = useSelector((state) => state.auth); const {id: currentId} = useSelector((state) => state.auth); const [content, setContent] = useState(''); const [photoURL, setPhotoURL] = useState(auth.profile_img_complete || '../../images/user-solid.svg'); //user-solid is the default image I want if the profile image link is null useEffect(() => { UserProfileService.getProfile().then( (response) => { setContent(response.data); if (response.data.profile_img_complete) setPhotoURL(response.data.profile_img_complete); }, (error) => { const _content = (error.response && error.response.data && error.response.data.message) || error.message || error.toString(); setContent(_content); } ); }, [currentId]); if (!currentUser) { return <Link to='/login' />; } return ( <div className='page'> <div className='profile-container'> <header className='jumbotron'> <h3> <strong id='profile-name'>{currentUser.username}</strong> Profile </h3> </header> <p> <img src={photoURL} alt='Avatar' className='avatar'></img> <strong>Token:</strong> {currentUser.accessToken.substring(0, 20)} ...{' '} {currentUser.accessToken.substr(currentUser.accessToken.length - 20)} </p> <p> <strong>Id:</strong> {currentUser.id} </p> <p> <strong>Email:</strong> {currentUser.email} </p> <strong>Authorities:</strong> <ul> {currentUser.roles && currentUser.roles.map((role, index) => <li key={index}>{role}</li>)} </ul> <button> <Link to={'/profile/edit'}>Edit Profile</Link> </button> </div> </div> ); }; export default Profile;