I need assistance on fetching my blob image from MySQL to browser.
I am using redux toolkit. So far, these are what I have. When I dispatch the imageId, I get isSuccess to be true on my Redux Dev Tool but I don't seem to know how to get the image to my browser.
Please, kindly help me solve this. I am stuck.
Thanks
CONTROLLER FILE on profileController.js
const getProfilePicture = async (req, res) => {
try {
const base64Data = await ProfilePic.findByPk(req.params.imageId);
res.send(base64Data);
} catch (error) {
res.status(500).send("error.message");
}
};
What I get on Postman when I hit the controller file route - the Database contains::: id(imageId), avatar(Blob Image), Description, createdAt, UpdatedAt
{
"id": "6dc38579-4e0f-4d4b-8777-7b6527408e72",
"avatar": {
"type": "Buffer",
"data": [
91,
111,
98,
106,
101,
99,
116,
32,
79,
98,
106,
101,
99,
116,
93
]
},
"description": null,
"createdAt": "2023-02-17T09:22:28.000Z",
"updatedAt": "2023-02-17T09:28:00.000Z"
}
SERVICE FILE on getProfilePictureService.js
import axios from "axios";
const API_URL = "http://localhost:4000/api/profile/";
const getProfilePicture = async (imageId, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
responseType: "arraybuffer",
};
try {
const response = await axios.get(
API_URL + "getProfilePicture/" + imageId,
config
);
const imageBuffer = Buffer.from(response.data, "binary");
const imageBlob = new Blob([imageBuffer], { type: "image/jpg" });
return URL.createObjectURL(imageBlob);
} catch (error) {
console.log(error);
}
};
const getProfilePictureService = {
getProfilePicture,
};
export default getProfilePictureService;
SLICE FILE on getProfilePictureSlice.js
import { createSlice, createAsyncThunk } from "#reduxjs/toolkit";
import getProfilePictureService from "./getProfilePictureService";
const initialState = {
getProPics: [],
isLoading: false,
isSuccess: false,
isError: false,
message: "",
};
//get profile picture
export const getProfilePicture = createAsyncThunk(
"profile/picture",
async (imageId, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await getProfilePictureService.getProfilePicture(imageId, token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
export const getProfilePictureSlice = createSlice({
name: "getProPic",
initialState,
reducers: {
reset: (state) => initialState,
},
extraReducers: (builder) => {
builder
.addCase(getProfilePicture.pending, (state) => {
state.isLoading = true;
})
.addCase(getProfilePicture.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.getProPics = action.payload;
})
.addCase(getProfilePicture.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
});
},
});
export const { reset } = getProfilePictureSlice.actions;
export default getProfilePictureSlice.reducer;
THE PROFILE BAR COMPONENT where I intend using the image ProfileBar.js
import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { getProfilePicture, reset } from "./features/getProfilePicture/getProfilePictureSlice";
const ProfileBar = ({ profile }) => {
const dispatch = useDispatch();
const [imageUrl, setImageUrl] = useState(null);
const imageId = profile.id; //I placed the profile id (which is the same as the image primary key in the database) in a constant
useEffect(() => {
dispatch(getProfilePicture(imageId)); //I dispatch that id here. I get isSuccess to be true after dispatching
return () => {
dispatch(reset());
};
}, [dispatch]);
useEffect(() => {
async function fetchImage() {
const url = await getProfilePicture(imageId);
setImageUrl(url); //I intended to use this to set the state after dispatching and isSuccess is true
}
fetchImage();
}, [imageId]);
return (
<div>
<img src={imageUrl} alt="Image" /> //this is supposed to get the image on browser
</div>
);
};
export default ProfileBar;
Related
i need help with redux toolkit, i'm using redux to fetch one array of objects but this not happen bellow is my redux code and get api.
GET API
export const getProductsApi = async () => {
const response = await fetch(
`${gateway.url}/products`,
{
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
}
);
const data = await response.json();
return data;
}
MY REDUX ACTION
import {
getProductsPending,
getProductsSuccess,
getProductsFailed,
} from "../../slices/get-products";
import { getProductsApi } from "../../../api/get-products";
export const getProducts = () => async (dispatch: any) => {
dispatch(getProductsPending());
try {
const response = await getProductsApi();
const data = response.data;
console.log('products redux here', data);
dispatch(getProductsSuccess(data));
} catch (error) {
dispatch(getProductsFailed(error));
}
};
REDUX SLICE
const getProductsSlice = createSlice({
name: "getProducts",
initialState,
reducers: {
getProductsPending: (state) => {
state.isLoading = true;
state.error = "";
},
getProductsSuccess: (state, action: PayloadAction<Product[]>) => {
state.isLoading = false;
state.products = action.payload;
state.error = "";
},
getProductsFailed: (state, action) => {
state.isLoading = false;
state.error = action.payload.error;
state.products = [];
},
},
});
const { reducer, actions } = getProductsSlice;
export const { getProductsPending, getProductsSuccess, getProductsFailed } =
actions;
export default reducer;
REDUX STORE
import { configureStore } from "#reduxjs/toolkit";
import getProductsReducer from "../redux/slices/get-products";
const store = configureStore({
reducer: {
products: getProductsReducer,
},
});
store.subscribe(() => console.log(store.getState()));
export default store;
in my browser console when is to appear the data, data appear so
whit my products array empty, and i don't know where is my error because anothers redux i made, i make like this and work correctly.
I appreciate every help to solve my question.
using redux tookit
I am working on a MERN app and I have a problem when updating items. I am getting rejections when sending a patch request and there is not much info for debugging to solve the problem. I will appreciate it if someone can point out some logic that is not correct in my code. Thank you in advance.
Here below is the logic I have implemented.
postService.js:
import axios from 'axios';
const API_URL = '/api/posts/';
const updatePost = async (postId, postData, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.patch(`${API_URL}/${postId}/`, postData, config);
if (response.data) {
return {
...response.data,
id: postId,
};
}
};
postSlice.js:
import { createSlice, createAsyncThunk } from '#reduxjs/toolkit';
import postService from './postService';
const initialState = {
posts: [],
isError: false,
isSuccess: false,
isLoading: false,
message: '',
};
export const updatePost = createAsyncThunk(
'posts/updatePost',
async (id, postData, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await postService.updatePost(id, postData, token);
} catch (error) {
const message =
(error.response.data.message) ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
export const postSlice = createSlice({
name: 'post',
initialState,
reducers: {
reset: (state) => initialState,
},
extraReducers: (builder) => {
builder
.addCase(updatePost.pending, (state) => {
state.isLoading = true;
})
.addCase(updatePost.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.posts = state.posts.map((post) =>
post.id === action.payload.id ? action.payload : post
);
})
.addCase(updatePost.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
});
},
});
export const selectAllPosts = (state) => state.posts.posts;
export const { reset } = postSlice.actions;
export default postSlice.reducer;
Form.js:
const Form = ({ postId, setPostId }) => {
const [formData, setFormData] = useState({
postCreator: '',
title: '',
body: '',
imageFile: '',
});
const dispatch = useDispatch();
const user = JSON.parse(localStorage.getItem('user'));
const post = useSelector((state) =>
postId ? state.posts.posts.find((post) => post._id === postId) : null
);
useEffect(() => {
if (post) setFormData(post);
}, [post]);
const clearPost = () => {
setPostId(0);
setFormData({
postCreator: '',
title: '',
body: '',
imageFile: '',
});
};
const handleSubmit = async (e) => {
e.preventDefault();
if (
!formData.postCreator &&
!formData.title &&
!formData.body &&
!formData.imageFile
) {
toast.warning(
'Please fill out all fields, and make sure you are also logged in'
);
} else if (postId) {
dispatch(updatePost(postId, formData));
console.log(postId);
} else {
dispatch(createPost(formData));
clearPost();
setPostId(null);
}
clearPost();
};
The second param of createAsyncThunk is the payloadCreator.
The first param of the payloadCreator is the arguments. The second param of payloadCreator is thunkAPI.
So you should combine id and postData into a single object to represent the arguments.
Update postSlice.js:
export const updatePost = createAsyncThunk(
'posts/updatePost',
async ({id, postData}, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await postService.updatePost(id, postData, token);
} catch (error) {
const message =
(error.response.data.message) ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
Update where you dispatch the updatePost thunk:
updatePost({
id: 123,
postData: {
foo: 'bar'
}
})
I am working on a MERN app with redux toolkit. Currently, I am facing a problem with my update functionality, when I click on the update button I can see in redux dev tools the request is rejected and in the console, the id is showing undefined while I am passing it. I am probably missing something in my code, if someone can point it out and explain that would be great. Thanks in advance. Here below are my code:
postService.js:
import axios from 'axios';
const API_URL = '/api/posts/';
const updatePost = async (_id, postData) => {
const response = await axios.patch(API_URL + _id, postData);
return response.data;
};
const postService = {
updatePost,
};
export default postService;
postSlice.js:
import { createSlice, createAsyncThunk } from '#reduxjs/toolkit';
import postService from './postService';
const initialState = {
posts: [],
isError: false,
isSuccess: false,
isLoading: false,
message: '',
};
export const updatePost = createAsyncThunk(
'posts/updatePost',
async ({ id, postData }, thunkAPI) => {
const { postCreator, title, body, imageFile } = postData;
try {
return await postService.updatePost(id, {
postCreator,
title,
body,
imageFile,
});
} catch (error) {
console.log(error.message);
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
export const postSlice = createSlice({
name: 'post',
initialState,
reducers: {
reset: (state) => initialState,
},
extraReducers: (builder) => {
builder
.addCase(updatePost.pending, (state) => {
state.isLoading = true;
})
.addCase(updatePost.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
const { id, postCreator, title, body, imageFile } = action.payload;
const existingPost = state.find((post) => post.id === id);
if (existingPost) {
existingPost.postCreator = postCreator;
existingPost.title = title;
existingPost.body = body;
existingPost.imageFile = imageFile;
}
})
.addCase(updatePost.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
export default postSlice.reducer;
Form.js:
const Form = ({ activeId, setActiveId }) => {
const [postData, setPostData] = useState({
postCreator: '',
title: '',
body: '',
imageFile: '',
});
const post = useSelector((state) =>
activeId ? state.posts.posts.find((post) => post._id === activeId) : null
);
const user = JSON.parse(localStorage.getItem('user'));
const dispatch = useDispatch();
useEffect(() => {
if (post) setPostData(post);
}, [post]);
const clearInputField = () => {
setActiveId(0);
setPostData({
postCreator: '',
title: '',
body: '',
imageFile: '',
});
};
const handleSubmit = async (e) => {
e.preventDefault();
if (activeId) {
dispatch(updatePost({ activeId, postData }));
clearInputField();
} else {
dispatch(createPost(postData));
clearInputField();
}
};
In the updatePost thunk in postSlice.js, you are attempting to destructure the variables { id, postData } from the payload creator args.
But in Form.js, you are sending an object { activeId, postData } when you dispatch updatePost.
So both id and postData will be undefined because neither exist on the object.
You could change it to:
dispatch(updatePost({id: activeId, postData: formData}))
I understand this has been asked before but so far no answers except someone making a syntax mistake. I have verified this against every tutorial I've seen online and I can't find the issue. It seems to be coming from the fullfilled extraReducer
import { createSlice, createAsyncThunk } from "#reduxjs/toolkit";
import axios from "axios";
const KEY = process.env.REACT_APP_API_KEY
const BASE_URL = process.env.REACT_APP_BASE_URL
const GLOBALVIEWS_API = `${BASE_URL}/countrymap`
const initialState = {
mapdata:{},
status: 'idle', //'idle', 'loading', 'succeeded', 'failed'
error:null
}
export const fetchMapData = createAsyncThunk(
'mapdata/fetchMapData',
async (id) => {
const response = await axios.get(
GLOBALVIEWS_API,
{
headers: {
'Content-Type': 'application/json',
'X-API-KEY': KEY,
},
params: {
titleId: id,
}
}
)
return response.data.Item;
}
)
const mapSlice = createSlice({
name: 'mapdata',
initialState,
reducers:{
addMapData: (state, { payload }) => {
state.mapdata = payload
}
},
extraReducers: {
[fetchMapData.pending]: () => {
console.log("Pending");
},
[fetchMapData.fulfilled]: (state, { payload }) => {
state.status = 'succeeded'
console.log("Succeeded", payload);
return {...state, mapdata: payload}
},
[fetchMapData.rejected]: () => {
console.log("Rejected");
},
}
})
// SELECTORS
export const getMapStatus = (state) => state.mapdata.status;
export const allMapData = (state) => state.mapdata.mapdata;
export const { addMapData } = mapSlice.actions;
export default mapSlice.reducer
In the component, nothing weird, and yes everything is imported
const {id} = useParams();
const dispatch = useDispatch();
const allmapdata = useSelector(allMapData)
const addmapdata = useSelector(addMapData)
const mapStatus = useSelector(getMapStatus)
useEffect(() => {
dispatch(fetchMapData(id))
lazy(setMap(allmapdata))
console.clear()
console.log("mapdata: ", allmapdata);
}, [id, allmapdata, dispatch])
You can see in my image below that my fetch is successful and I am getting data. So how do I get rid of this error? Thanks in advance.
This is the issue:
state.status = 'succeeded'
console.log("Succeeded", payload);
return {...state, mapdata: payload}
That is indeed both a "mutation of the existing state" and a "return of a new value", and that's exactly what the error is warning you about.
You can change that to:
state.status = 'succeeded'
state.mapdata = action.payload
i dont know where is the trouble. but when i tried to login, it dont wanna navigate into the next pages and stuck in modal login. please tell me whats wrong with my code?
let navigate = useNavigate();
const dispatch = useContext(UserContext);
const state = useContext(UserContext);
// console.log(state);
const [form, setForm] = useState({
email: "",
password: "",
});
const { email, password } = form;
const handleChange = (e) => {
setForm({
...form,
[e.target.name]: e.target.value,
});
};
const handleSubmitLog = async (e) => {
try {
e.preventDefault();
const config = {
headers: {
"Content-type": "application/json",
},
};
const body = JSON.stringify(form);
const response = await API.post("/login", body, config);
console.log(response.data);
if (response?.status == 200) {
dispatch({
type: "LOGIN_SUCCESS",
payload: response.data.data,
});
if (response.data.data.status == "admin") {
navigate('/admin')
} else {
navigate('/userid')
}
}
} catch (error) {
console.log(error);
}
}
here is the response in console, i dont know why this dispatch can not work well
{
"status": "Success",
"data": {
"users": {
"name": "mr.x",
"email": "mr.x#mail.com",
"token": "asfsa"
}
}
}
TypeError: dispatch is not a function
at handleSubmitLog (header.js:59:1)
and here is the body from userContext file. please check it and tell me if my code is wrong
export const UserContext = createContext();
const initialState = {
isLogin: false,
user: {},
};
const reducer = (state, action) => {
const { type, payload } = action;
switch (type) {
case "USER_SUCCESS":
case "LOGIN_SUCCESS":
localStorage.setItem("token", payload.token)
return {
isLogin: true,
user: payload,
};
case "AUTH_ERROR":
case "LOGOUT":
localStorage.removeItem("token")
return {
isLogin: false,
user: {},
};
default:
throw new Error();
}
};
export const UserContextProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<UserContext.Provider value={[state, dispatch]}>
{children}
</UserContext.Provider>
);
};
The UserContext value is an array [state, dispatch]:
<UserContext.Provider value={[state, dispatch]}>
{children}
</UserContext.Provider>
But the component is not correctly accessing the context value:
const dispatch = useContext(UserContext);
const state = useContext(UserContext);
Here both dispatch and state have are the same context value of [state, dispatch].
You need only one useContext(UserContext) access, either of the following:
Save the entire context value and use array indexing:
const userContext = useContext(UserContext);
...
// userContext[0]; state object/value
// userContext[1]; dispatch function
...
userContext[1]({
type: "LOGIN_SUCCESS",
payload: response.data.data,
});
Save the state and dispatch values directly using array destructuring assignment:
const [state, dispatch] = useContext(UserContext);
...
dispatch({
type: "LOGIN_SUCCESS",
payload: response.data.data,
});
Try this:
const { state, dispatch } = useContext(AppContext)