I have been working on a project where I am trying to update my selected data but Axios didn't Update it even after giving a success msg.
User Response it returns from axios:-
completed: true
date: "2021-02-28"
mupp_path: "PATH 1 - LIVING YOUR WHY - Build/Apply/Inspire/Spread (BAIS) – Finding & Achieving Meaning and Purpose in work and life"
project_name: "Design and Test the Training Content for the i-Infinity 3 verticals "
selected: true
task_id: 14
task_name: "This is adding a new task to chekc full inbox functionality "
task_type: "THIS_WEEK"
Actions.js
export const taskTodayUnselect = (id) => async (dispatch) => {
try {
dispatch({ type: types.UNSELECTED_TASK_TODAY_REQUEST });
const { data } = await axios.put(
selectTaskForToday,
{
task_id: id,
selected: false,
},
{
headers: {
Authorization: `JWT ${token}`,
},
}
);
if (data) {
return dispatch({ type: types.UNSELECTED_TASK_TODAY_SUCCESS, payload: data });
}
} catch (error) {
return dispatch({ type: types.UNSELECTED_TASK_TODAY_FAILURE, payload: error });
}
};
thisweek.js
export default function ThisWeek() {
const unselectTaskTodayAPI = (id) => {
dispatch(taskTodayUnselect(id)).then((response) => {
let result = response.payload;
console.log(result);
if (result.success === 'true') {
notifySuccess(result.message);
fetchTaskData(categoryID);
}
});
};
const selectTask = (item) => {
if (item.selected) {
unselectTaskTodayAPI(item);
console.log('unselect');
} else {
selectTaskTodayAPI(item.task_id);
}
};
return (
<TaskDataComponent
item={item}
key={item.task_id}
label="This Week"
selectTask={selectTask}
/>
);
Don't Worry about the TaskDataComponent , it only handle the onClick function which invoke the selectedTask function
Related
I'm trying to create a custom hook and i would like to catch an error on the api call in order to change the display. This is the custom hook :
function useBook() {
const [book, setBook] = useState<Book | any>()
const [loading, setLoading] = useState(true)
const [error, setError] = useState<Error | boolean>(false)
useEffect(() => {
const fetchData = async () => {
try {
const data = await getBook(Number(Object.values(id)))
setBook(data)
setLoading(false)
} catch (error) {
setError(true)
setLoading(false)
}
}
fetchData()
dispatch({ type: 'auth/isLogin' })
}, [])
return { book, loading, error }
}
And this is the api function :
export type Book = {
title: string
id: number
authorName: string
authorSurname: string
coverImage: string
releaseDate: string
pages: number
price: number
}
export type Error = {
isError: boolean
}
async function getBook(id: number): Promise<Book | Error> {
try {
const { data } = await axios.get<Book>(
`http://localhost:3000/books/${id}`,
{
headers: {
Accept: 'application/json',
},
}
)
return data
} catch (error) {
console.log('Error is : ', error)
return {
isError: true,
}
}
}
The problem is that I never enter in the 'catch error' case and thus the state of error is always false. How could I change that ?
Trying throwing an error instead of return:
export type Book = {
title: string
id: number
authorName: string
authorSurname: string
coverImage: string
releaseDate: string
pages: number
price: number
}
export type Error = {
isError: boolean
}
async function getBook(id: number): Promise<Book | Error> {
try {
const { data } = await axios.get<Book>(
`http://localhost:3000/books/${id}`,
{
headers: {
Accept: 'application/json',
},
}
)
return data
} catch (error) {
console.log('Error is : ', error)
throw new Error("error")
}
}
Using react.js & firebase
The code below represents a simple button which increases/decreases +1/-1 whenever its clicked. It also updates one of the documents on the backend (using firebase). Everything seems to work fine on the surface but not on firebase. When you click on the button, it'll show +1 on the UI and console.log but not on firebase. In other words when plusCount state is at 0, it shows +1 on firebase and when plusCount state is at +1, it shows 0 on firebase. How can I fix this to make sure it shows the same number on the frontend and the backend? I also added the useFirestore hook component below, there may be a mistake that I'm unaware of in there somewhere.
Thank you for any help.
Button component:
import React, { useState } from 'react';
import { useFirestore } from "../../hooks/useFirestore"
export default function Testing({ doc }) {
const { updateDocument } = useFirestore('projects')
const [plusActive, setPlusActive] = useState(false)
const [plusCount, setPlusCount] = useState(0)
function p() {
setPlusActive(prevState => !prevState);
plusActive ? setPlusCount(plusCount - 1) : setPlusCount(plusCount + 1)
}
const handlePlus = (e) => {
e.preventDefault();
p();
updateDocument(doc.id, {
votes: plusCount
})
}
console.log(plusCount)
return (
<div>
<button onClick={handlePlus}>like | {plusCount}</button>
</div>
)
}
useFirestore hook component:
import { projectFirestore, timestamp } from "../firebase/config"
let initialState = {
document: null,
isPending: false,
error: null,
success: null,
}
const firestoreReducer = (state, action) => {
switch (action.type) {
case 'IS_PENDING':
return { isPending: true, document: null, success: false, error: null }
case 'ADDED_DOCUMENT':
return { isPending: false, document: action.payload, success: true, error: null }
case 'DELETED_DOCUMENT':
return { isPending: false, document: null, success: true, error: null }
case 'ERROR':
return { isPending: false, document: null, success: false, error: action.payload }
case "UPDATED_DOCUMENT":
return { isPending: false, document: action.payload, success: true, error: null }
default:
return state
}
}
export const useFirestore = (collection) => {
const [response, dispatch] = useReducer(firestoreReducer, initialState)
const [isCancelled, setIsCancelled] = useState(false)
// collection ref
const ref = projectFirestore.collection(collection)
// only dispatch if not cancelled
const dispatchIfNotCancelled = (action) => {
if (!isCancelled) {
dispatch(action)
}
}
// add a document
const addDocument = async (doc) => {
dispatch({ type: 'IS_PENDING' })
try {
const createdAt = timestamp.fromDate(new Date())
const addedDocument = await ref.add({ ...doc, createdAt })
dispatchIfNotCancelled({ type: 'ADDED_DOCUMENT', payload: addedDocument })
}
catch (err) {
dispatchIfNotCancelled({ type: 'ERROR', payload: err.message })
}
}
// delete a document
const deleteDocument = async (id) => {
dispatch({ type: 'IS_PENDING' })
try {
await ref.doc(id).delete()
dispatchIfNotCancelled({ type: 'DELETED_DOCUMENT' })
}
catch (err) {
dispatchIfNotCancelled({ type: 'ERROR', payload: 'could not delete' })
}
}
// update a document
const updateDocument = async (id, updates) => {
dispatch({ type: "IS_PENDING" })
try {
const updatedDocument = await ref.doc(id).update(updates)
dispatchIfNotCancelled({ type: "UPDATED_DOCUMENT", payload: updatedDocument })
return updatedDocument
}
catch (error) {
dispatchIfNotCancelled({ type: "ERROR", payload: error })
return null
}
}
useEffect(() => {
return () => setIsCancelled(true)
}, [])
return { addDocument, deleteDocument, updateDocument, response }
}```
For your use-case, you should useEffect() to listen the changes for plusCount. See code below:
useEffect(() => {
updateDocument('test', {
votes: plusCount
})
}, [plusCount]);
const handlePlus = (e) => {
e.preventDefault();
setPlusActive(prevState => !prevState);
plusActive ? setPlusCount(plusCount - 1) : setPlusCount(plusCount + 1)
}
Everytime you click the button it will listen to the changes of plusCount which then the updateDocument will also be triggered together with the updated state. See below screenshot for the result:
As you can see, the frontend and backend is now aligned.
You can find more information by checking out this documentation.
Just want to update my database after every time pushed the More or Less button (Please take a look at my project ) but the problem is doesn't send the first request and after second request data will send to the firebase and update the special part
react and redux don't have any problem (the base of this project wrote with them) as I asked about it of a redux consultant .
whole the problem come back to involving my app with firebase
Demo :https://zealous-allen-932726.netlify.app/ .
Github : https://github.com/alibidjandy/burger
this is the Api configuration :
import { current } from "#reduxjs/toolkit";
import { createApi, fetchBaseQuery } from
"#reduxjs/toolkit/query/react";
import {
BurgerType,
OrderType,
} from "../components/Layouts/burger/burgerSlice/burgerSlice";
export const burgerApi = createApi({
reducerPath: "burgerApi",
tagTypes: ["Ingredients"],
baseQuery: fetchBaseQuery({
baseUrl:
"https://burger-order-brown-default-rtdb.europe-west1.firebasedatabase.app",
}),
endpoints: (builder) => ({
getIngredients: builder.query<BurgerType, undefined>({
query: () => {
return { url: "/burger.json", method: "GET" };
},
providesTags: ["Ingredients"],
}),
editIngredients: builder.mutation({
query: ({ burger, ing, value, resetToZero }) => {
return {
url: `/.json`,
method: "PATCH",
body: { burger },
};
},
async onQueryStarted(
{ ing, value, resetToZero },
{ dispatch, queryFulfilled }
) {
const patchResult = dispatch(
burgerApi.util.updateQueryData(
"getIngredients",
undefined,
(draft) => {
if (resetToZero) {
const ingredients = draft.ingredients;
ingredients.map((ing) => {
if (ing.Qty) {
ing.Qty = 0;
}
return ing;
});
draft.totalCost = 0;
} else {
const ingredient = draft.ingredients[ing.id]!;
draft.totalCost -= ingredient.Qty! * ingredient.cost!;
ingredient.Qty! += value;
draft.totalCost += ingredient.Qty! * ingredient.cost!;
draft.totalCost.toFixed(2);
if (draft.totalCost < 0) {
draft.totalCost = 0;
}
}
}
)
);
try {
await queryFulfilled;
} catch {
patchResult.undo();
}
},
}),
setOrders: builder.mutation({
query: ({ name, email, postalCode, street, burger }) => {
return {
url: "/orders/.json",
method: "POST",
body: { name, email, postalCode, street, burger },
};
},
}),
getOrders: builder.query<OrderType[], undefined>({
query: () => {
return { url: "/orders.json", method: "GET" };
},
providesTags: ["Ingredients"],
}),
}),
});
export const { editIngredients, getIngredients } = burgerApi.endpoints;
export const {
useGetIngredientsQuery,
useEditIngredientsMutation,
useGetOrdersQuery,
useSetOrdersMutation,
} = burgerApi;
I have this weird error in my React app at the moment. I am sending an api request and I want to do something if it succeeds and something else if I get an error back. The api requests succeeds, the post is getting approved, but the catch clause is executed instead of then.
Can you see something in this code that might make that happen?
The request which I am talking about is the Request.post one... the large one that ecompasses a few other requests.
export const approvePostSubmission = (post, date) => dispatch => {
const label = `${post.campaign_product_name} on ${moment(date).format('LL')}`;
if (post.post_type === 3) {
dispatch(sendGoogleEvent(GOOGLE_EVENT.STORY.APPROVE, label));
} else {
dispatch(sendGoogleEvent(GOOGLE_EVENT.POST.APPROVE, label));
}
dispatch({
type: APPROVE_POST_PENDING,
});
return Request.post(
API_ENDPOINT.POST_APPROVE(post.id),
{ publish_at: date },
false
)
.then(response => {
const { selectedContent } = store.getState().inbox;
dispatch(getUserWallet());
dispatch({
type: APPROVE_POST_SUCCESS,
});
const getPostTypeText = post_type => {
switch (post_type) {
case 3:
return 'Story';
case 4:
return 'IGTV Post';
case 5:
return 'Carousel';
case 6:
return 'IG Live';
default:
return 'Post';
}
};
const postType = getPostTypeText(selectedContent.post.post_type);
setTimeout(() => {
toast.show(
<p>
{`Woo! You approved a ${postType}! It will be published on `}
<RouterLink
to="/calendar"
color="#0dd36b"
onClick={e => toast.hide()}
>
{`${moment(date).format('LL')} 🙌`}
</RouterLink>
</p>,
{
type: 'success',
dismiss: true,
}
);
}, 100);
// Send slack bot message
Request.post(`${SLACKBOT.URL}/new-post`, {
post_status: 1,
post_type: selectedContent.post.post_type,
post_id: selectedContent.post.id,
campaign_name: selectedContent.post.campaign_product_name,
influencer_id: selectedContent.influencer.id,
influencer_name: selectedContent.influencer.full_name,
campaign_id: selectedContent.post.campaign_id,
post_image: selectedContent.post.image_url,
slack_channel: SLACKBOT.CHANNELS.NEW_POST,
})
.then(data => {})
.catch(err => console.error(err));
return response;
})
.catch(err => {
setTimeout(() => {
dispatch({
type: APPROVE_POST_FAIL_SHOW_ERR,
payload: !!err.response
? err.response.data.message
: 'Unable to approve post!',
});
!!err.response &&
toast.show(
`${err.response.data.message || err.response.data.error} 🚫`,
{ type: 'fail' }
);
setTimeout(() => {
dispatch({
type: APPROVE_POST_FAIL,
});
}, 3000);
}, 500);
});
};
I am trying to chain dispatches with redux-thunk. I have 2 action creator as below:
getResourceLinks:
export const getResourceLinks = () => {
return dispatch => {
let req = {
url: getRootUrl(),
header: {
Accept: 'application/json'
}
};
return request(req).then(res => {
dispatch({
type: ActionTypes.RESOURCE.LOAD_URL_SUCCESS,
payload: res.body
});
}).catch(err => {
dispatch({
type: ActionTypes.RESOURCE.LOAD_URL_ERROR,
payload: err
});
});
}
};
and loadAppliances:
export const loadAppliances = () => {
return (dispatch, getState) => {
return dispatch(getResourceLinks()).then(res => {
const {resources} = getState();
let req = {
url: getResourceLink(Resources.Appliances, res.body),
header: {
Accept: 'application/json'
}
};
request(req).then(res1 => {
dispatch({
type: ActionTypes.APPLIANCE.LOAD_SUCCESS,
payload: res1.body
});
}).catch(err => {
dispatch({
type: ActionTypes.APPLIANCE.LOAD_ERROR,
payload: err
});
});
});
};
};
I am facing with an error: Uncaught TypeError: Cannot read property 'then' of undefined at line 3 in loadAppliances action. Promise was returned correctly, wasn't it? Am I doing wrong something? I've seen carefully examples of thunk-redux but I don't still find out what was wrong.
Update. Here is request:
import superagent from 'superagent';
import superagentPromisePlugin from 'superagent-promise-plugin';
import {RequestMethods} from '../constant';
const request = ({url, method = RequestMethods.GET, param, body, header}) => {
let methodStr;
switch (method) {
case RequestMethods.POST:
methodStr = 'POST';
break;
case RequestMethods.PUT:
methodStr = 'PUT';
break;
case RequestMethods.DELETE:
methodStr = 'DELETE';
break;
default:
methodStr = 'GET';
break;
}
let req = superagent(methodStr, url).use(superagentPromisePlugin);
//set header
if (header) {
req.set(header)
}
//set param
if (param) {
req.query(param)
}
//set body
if (body) {
req.send(body)
}
return req;
};
export default request;
The problem here is that dispatch does not return your promise. It actually returns the dispatched action itself. (reference).
return dispatch(getResourceLinks()).then(res => {
^--- this is the problem
The way I would approach this is to dispatch an action after your first successful call and store any pertinent information in the state, then dispatch the next call and store its response.
Example
const getResourceLinks = () => {
return request({
url: getRootUrl(),
header: {
Accept: 'application/json'
}
});
};
const getAppliances = (appliances) => {
return request({
url: getResourceLink(Resources.Appliances, appliances),
header: {
Accept: 'application/json'
}
})
};
export const loadAppliances = () => {
return (dispatch, getState) => {
getResourceLinks()
.then(res => {
dispatch({
type: ActionTypes.RESOURCE.LOAD_URL_SUCCESS,
payload: res.body
});
return getAppliances(res.body)
.then(res1 => {
dispatch({
type: ActionTypes.APPLIANCE.LOAD_SUCCESS,
payload: res1.body
});
})
.catch(err => {
dispatch({
type: ActionTypes.APPLIANCE.LOAD_ERROR,
payload: err
});
});
})
.catch(err => {
dispatch({
type: ActionTypes.RESOURCE.LOAD_URL_ERROR,
payload: err
});
});
}
}
You also might want to take a look at redux-saga