data from useQuery i.e. react query is returning undefined - reactjs

this is my api middleware caller that i have created:
/* eslint-disable #typescript-eslint/no-var-requires */
// /* eslint-disable no-import-assign */
import Axios from 'axios';
import * as queryString from 'query-string';
const caseConverter = require('change-object-case');
import { cleanParams } from '_utilities/common';
import { REQUEST_TYPES } from './constants';
import { useLoginUser } from '_store/user';
interface IAuth {
method?: string;
url?: string;
data?: any;
params?:any,
contentType?:string,
isTransformRequestRequired?:boolean
}
export function apiCaller(
{
method = REQUEST_TYPES.GET,
url = '',
params = {},
data = {},
contentType = 'application/json',
isTransformRequestRequired = true,
}:IAuth,
) {
const user = useLoginUser.getState().user;
const token = user?.data?.token || '';
// caseConverter.options = {recursive: true, arrayRecursive: true};
return Axios({
method,
url,
params,
paramsSerializer: queryParams => queryString.stringify(caseConverter.snakeKeys(cleanParams(queryParams))),
data,
transformRequest: [reqData => isTransformRequestRequired
? JSON.stringify(caseConverter.toSnake(reqData))
: reqData],
transformResponse: [(respData) =>
{
if(typeof respData === 'string')
return JSON.parse(respData)
else {
return respData
}
}],
headers: {
Authorization: user !== null ? `Token ${ token }` : '',
'Content-Type': contentType,
},
responseType: 'json',
validateStatus: status => status >= 200 && status < 300,
})
.then(({ data: resp }) => resp)
.catch(error => {
console.log(error,'error')
// if user session is expired from server and got 401, will logout the user from application
if(error.response.status === 401) {
// store.dispatch(logoutSuccess());
} else {
throw(error);
}
});
}
this is where I am calling my apiCaller:
import { apiCaller } from '../api-caller';
import { ENDPOINTS, REQUEST_TYPES } from '../constants';
import moment from 'moment';
export const usersApi = async (params:any) => {
const res = await apiCaller(
{
method: REQUEST_TYPES.GET,
url: `${ENDPOINTS.USERS}/`,
params:{
...params,
startDatetime: params.startDatetime ? moment(params.startDatetime).utc().format('YYYY-MM-DD H:mm:ss') : '',
endDatetime: params.endDatetime ? moment(params.endDatetime).utc().format('YYYY-MM-DD H:mm:ss') : '',
},
},
);
return res;
}
this is where I am using useQuery to fetch data from backend:
import { useQuery } from '#tanstack/react-query'
import { usersApi } from '_api/users'
import { useAdminUser } from 'pages/Admin/AdminUsers/_store'
const filters = useAdminUser.getState().filters
export const useCreateProfile = () => {
const query = ['cashierShifts']
return useQuery(query, () => {
usersApi(filters)
})
}
and this is where I am using this in my component:
import React, { useState } from 'react'
import { Table } from 'antd'
import { useCreateProfile } from '_services/CashierProfile'
const columns = [
{
title: 'Day',
dataIndex: 'day',
key: 'day',
},
{
title: 'Shift',
dataIndex: 'shift',
key: 'shift',
},
{
title: 'startTime',
dataIndex: 'start',
key: 'start',
},
{
title: 'endTime',
dataIndex: 'end',
key: 'end',
},
{
title: 'Mart',
dataIndex: 'mart',
key: 'mart',
},
]
const CashierShifts = () => {
const { data, isError, isLoading, isSuccess } = useCreateProfile()
console.log(data, 'react-query')
const [result, setResult] = useState([
{
id: 54,
tile: 'slots 1',
date: '22-10-2203',
startTime: '8:00',
mart: {
id: 21,
martName: 'Johar Town',
},
endTime: '12:00',
cashier: {
name: 'Jamal',
id: 54,
},
},
{
id: 54,
tile: 'slots 1',
date: '22-10-2203',
startTime: '8:00',
mart: {
id: 21,
martName: 'Johar Town',
},
endTime: '12:00',
cashier: {
name: 'Jamal',
id: 54,
},
},
{
id: 54,
tile: 'slots 1',
date: '22-10-2203',
startTime: '8:00',
mart: {
id: 21,
martName: 'Johar Town',
},
endTime: '12:00',
cashier: {
name: 'Jamal',
id: 54,
},
},
{
id: 54,
tile: 'slots 1',
date: '22-10-2203',
startTime: '8:00',
mart: {
id: 21,
martName: 'Johar Town',
},
endTime: '12:00',
cashier: {
name: 'Jamal',
id: 54,
},
},
])
const dataSource = result.map((a) => ({
day: a.date,
shift: a.tile,
start: a.startTime,
end: a.endTime,
mart: a.mart.martName,
}))
return (
<div>
<Table columns={columns} dataSource={dataSource} />
</div>
)
}
export default CashierShifts
the problem is when i am using my react query hook in my component but the data is returning undefined here.
const { data, isError, isLoading, isSuccess } = useCreateProfile()
console.log(data, 'react-query')

return useQuery(query, () => {
return usersApi(filters)
})

Related

Cannot access 'transactionId' before initialization

Why is transactionId not activating inside the useEffect hook?
It is an edit route through the context api. It strange because react-router-dom picks up the transactionId in the url.
edit transaction modal
let history = useHistory();
const { transaction, editTransaction } = useContext(GlobalContext);
const [selectedTransaction, setSelectedTransaction] = useState({
id: null,
category: "",
heading: "",
description: "",
subHeading: "",
author: "",
});
const transactionId = match.params.id;
useEffect(() => {
const transactionId = transactionId;
const selectedTransaction = transaction.find(
(t) => t.id === parseInt(transactionId)
);
setSelectedTransaction(selectedTransaction);
}, [transactionId, transaction]);
const [open, setOpen] = useState(true);
const cancelButtonRef = useRef(null);
const onSubmit = (e) => {
editTransaction(selectedTransaction);
history.push("/");
};
const handleOnChange = (transactionKey, val) =>
setSelectedTransaction({
...selectedTransaction,
[transactionKey]: val,
});
let formData = {
name: setSelectedTransaction.name,
amount: setSelectedTransaction.amount,
category: setSelectedTransaction.category,
};
global state
import React, { createContext, useReducer, useEffect } from "react";
import AppReducer from "./AppReducer";
//Initial State
const initialState = {
transactions: [
{
id: "1",
name: "Rent",
href: "#",
category: "expense",
amount: 1000,
currency: "USD",
status: "processing",
date: "July 1, 2020",
datetime: "2020-07-11",
type: "Bills",
},
{
id: "2",
name: "IRS",
href: "#",
category: "income",
amount: 5000,
currency: "USD",
status: "success",
date: "July 18, 2020",
datetime: "2020-07-18",
type: "Extra Income",
},
{
id: "3",
name: "Paypal",
href: "#",
category: "income",
amount: 15000,
currency: "USD",
status: "success",
date: "July 18, 2020",
datetime: "2020-07-18",
type: "Income",
},
{
id: "4",
name: "AT&T",
href: "#",
category: "expense",
amount: 2000,
currency: "USD",
status: "success",
date: "July 11, 2020",
datetime: "2020-07-11",
type: "Phone",
},
],
totalTransactionCount: 4,
};
//Create context
export const GlobalContext = createContext(initialState);
//Provider component
export const GlobalProvider = ({ children }) => {
const [state, dispatch] = useReducer(AppReducer, initialState);
const { totalTransactionCount, transactions } = state;
//Actions
function deleteTransaction(id) {
dispatch({
type: "DELETE_TRANSACTION",
payload: id,
});
}
function addTransaction(transaction) {
dispatch({
type: "ADD_TRANSACTION",
payload: transaction,
});
}
const editTransaction = (transaction) => {
dispatch({
type: "EDIT_TRANSACTION",
payload: transaction,
});
};
useEffect(() => {
dispatch({
type: "SET_TRANSACTION_COUNT",
payload: transactions.length,
});
}, [transactions]);
return (
<GlobalContext.Provider
value={{
transactions: state.transactions,
totalTransactionCount,
deleteTransaction,
addTransaction,
editTransaction,
}}>
{children}
</GlobalContext.Provider>
);
};
reducer
export default (state, action) => {
switch (action.type) {
case "DELETE_TRANSACTION":
return {
...state,
transactions: state.transactions.filter(
(transaction) => transaction.id !== action.payload
),
};
case "EDIT_TRANSACTION":
const updatedTransaction = action.payload;
const updatedTransactions = state.transactions.map((transaction) => {
if (transaction.id === updatedTransaction.id) {
return updatedTransaction;
}
return transaction;
});
return {
...state,
transactions: updatedTransactions,
};
case "ADD_TRANSACTION":
return {
...state,
transactions: [action.payload, ...state.transactions],
};
case "SET_TRANSACTION_COUNT":
return {
...state,
totalTransactionCount: action.payload,
};
default:
return state;
}
};

Apollo client not calling with correct variables

I have a query like
export default gql`
query getStatus($statusInput: StatusInput!) {
getStatus(statusInput: $statusInput) {
canAccess
isCorrect
}
}
`;
And then I have a hook that uses this query
const useStatus = () => {
const [someId] = useId();
return useQuery<{ getStatus: StatusResponse }>(getStatus, {
variables: { statusInput: { id: someId, numValue: 1 } },
fetchPolicy: 'no-cache',
skip: !cartId,
ssr: false,
});
};
And I am using it in my component as
const { data: statusData, loading: dataLoading, variables } = useStatus();
In the the component.spec.tsx I have
const mocks = [
{
request: {
query: getStatus,
variables: {
statusInput: {
id: '1234',
numValue: 55,
},
},
},
result: {
data: {
getStatus: {
__type: 'StatusResponse',
canAccess: true,
isCorrect: true
},
}
},
},
];
and inside the test I have
const { queryByTestId, container } = renderWithProviders(
<MockedProvider mocks={mocks} addTypename={true} cache={inMemoryCache}>
<Component />
</MockedProvider>,
{ mockedContextData: someContextMocks }
);
But when I print variables in the component, I get
{ checkoutStatusInput: { id: '', numValue: 1 } }
instead of the values I passed in the mocks.
Did I miss something?

How to add the two map() function(bind) and display into the page? Issue on calling two maps

In reactjs, How to add the two map() function(bind) and display into the page? Facing Issue on calling two map in reactjs
import React from "react";
import Select from "react-select";
export default class Sampletest extends React.Component {
constructor(props) {
super(props);
this.state = {
years: {
options: [
{ value: '2021', label: '2021' },
{ value: '2020', label: '2020' },
{ value: '2019', label: '2019' },
{ value: '2018', label: '2018' },
{ value: '2017', label: '2017' },
{ value: '2016', label: '2016' },
],
value: null
},
categories: {
options: [
{ value: '0', label: 'Incomplete' },
{ value: '1', label: '80G' },
{ value: '2', label: '80G' },
{ value: '3', label: 'Sports' },
{ value: '4', label: 'Social welfare' },
{ value: '5', label: 'Professional' },
{ value: '6', label: 'Health' },
{ value: '7', label: 'Food and Nutrition' },
{ value: '8', label: 'Education' }
],
value: null
},
Activity: {
options: [
{ value: '0', label :'My Causes'},
{ value: '1', label :'Liked Causes'},
{ value: '2', label :'Commented Causes'},
{ value: '3', label :'Pledged Causes'}
],
value: null
} ,
// Details:[]
};
}
onSelectChange(name, value) {
this.setState(
(prev) => {
return {
...prev,
[name]: {
...prev[name],
value: value.value
}
};
},
() => {
let url =
"http://localhost:88888/api/GetProfile/Get_MyPostDetails?id=" +
this.state.Activity.value + "&Year=" +
this.state.years.value +
"&CategoryID=" +
this.state.categories.value
;
let user = JSON.parse(localStorage.getItem("user"));
const accessToken = user;
console.log(accessToken);
//console.log("hi");
fetch(url, {
method: "GET",
headers: {
"Content-type": "application/json",
Accept: "application/json",
Authorization: "Bearer " + accessToken,
"Access-Control-Allow-Headers": "Access-Control-Request-Headers "
}
//body:JSON.stringify(data)
})
.then((response) => response.json())
.then((data) => {
this.setState({
Details: data
});
console.log("Filter", data);
// console.log(emps.profile_dateOfAnniversary);
});
}
);
}
render() {
const {Details} = this.state;
return (
<div>
{Object.keys(this.state).map((name, i) => {
return (
<Select
key={i}
placeholder={name}
options={this.state[name].options}
onChange={this.onSelectChange.bind(this, name)}
/>
);
})}
{Details.map(emp => (
<div>
<div>{emp.profile_name} </div>
</div>
))}
</div>
);
}
}
While Compile this code , Facing issue as--> TypeError: Cannot read properties of undefined (reading 'map').
I have added my code , we need to add map method in the program for output and I have use this class component and calling this page into another page and display the object into array of object.
Initialize Details as Array while declaring state.
it will be undefined on mounting face so you get the error
and check on response you are getting this response as array.

.map is undefined when mapping through the profile.education array

I'm experiencing some difficulty with trying to map through an objects property which is an array of objects. I get back an error message that .map is undefined, basically saying there is no array. The array i want to map through is education. At times I also get a proxy error that the route is timing out and this loses the profile data i'm fetching and the profile object is empty. Is there anyway to fix this too.
My model:
import mongoose from 'mongoose'
const profileSchema = new mongoose.Schema(
{
experience: [
{
title: {
type: String,
required: true,
},
company: {
type: String,
required: true,
},
location: {
type: String,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
education: [
{
level: {
type: String,
required: true,
enum: [
'None',
'GCSE or equivalent',
'A-Level or equivalent',
'Certificate of Higher Education',
'Diploma of Higher Education',
'Bachelors',
'Masters',
'PhD',
],
},
school: {
type: String,
required: true,
},
fieldofstudy: {
type: String,
required: true,
},
city: {
type: String,
required: true,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
},
],
skills: [
{
name: {
type: String,
required: true,
},
yearsExperience: {
type: Number,
required: true,
},
},
],
additionalInfo: {
desiredJobTitle: {
type: String,
},
desiredJobType: {
type: [String],
},
desiredSalary: {
type: Number,
},
readyToWork: {
type: Boolean,
default: false,
},
relocate: {
type: Boolean,
default: false,
},
},
savedJobs: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Job',
},
],
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
},
{ timestamps: true }
)
const Profile = mongoose.model('Profile', profileSchema)
export default Profile
My action:
import axios from 'axios'
import {
PROFILE_DETAILS_REQUEST,
PROFILE_DETAILS_SUCCESS,
PROFILE_DETAILS_FAIL,
PROFILE_CREATE_REQUEST,
PROFILE_CREATE_SUCCESS,
PROFILE_CREATE_FAIL,
PROFILE_CREATE_EDUCATION_REQUEST,
PROFILE_CREATE_EDUCATION_SUCCESS,
PROFILE_CREATE_EDUCATION_FAIL,
} from '../constants/profileConstants'
import { setAlert } from './alertActions'
export const getCurrentProfile = () => async (dispatch, getState) => {
try {
dispatch({ type: PROFILE_DETAILS_REQUEST })
const {
userLogin: { userData },
} = getState()
const config = {
headers: {
Authorization: `Bearer ${userData.token}`,
},
}
const { data } = await axios.get('/api/v1/profile/me', config)
dispatch({
type: PROFILE_DETAILS_SUCCESS,
payload: data,
})
} catch (error) {
dispatch({
type: PROFILE_DETAILS_FAIL,
payload:
error.response && error.response.data.error
? error.response.data.error
: null,
})
}
}
My reducer:
export const profileDetailsReducer = (state = { profile: {} }, action) => {
switch (action.type) {
case PROFILE_DETAILS_REQUEST:
return {
...state,
loading: true,
}
case PROFILE_DETAILS_SUCCESS:
return {
loading: false,
profile: action.payload,
}
case PROFILE_DETAILS_FAIL:
return {
loading: false,
error: action.payload,
}
case PROFILE_DETAILS_RESET:
return {
profile: {},
}
default:
return state
}
}
My dashboard component:
import React, { useEffect } from 'react'
import Moment from 'react-moment'
import { useDispatch, useSelector } from 'react-redux'
import { getCurrentProfile } from '../actions/profileActions'
import Loader from '../components/layout/Loader'
import DashboardActions from '../components/dashboard/DashboardActions'
const Dashboard = ({ history }) => {
const dispatch = useDispatch()
const profileDetails = useSelector((state) => state.profileDetails)
const { loading, error, profile } = profileDetails
const userLogin = useSelector((state) => state.userLogin)
const { userData } = userLogin
console.log(profile)
useEffect(() => {
if (!userData) {
history.push('/login')
} else {
dispatch(getCurrentProfile())
}
}, [dispatch, history, userData])
return (
<>
<h1 class='mb-4'>Dashboard</h1>
<p>Welcome {userData && userData.name}</p>
<br />
{loading ? (
<Loader />
) : (
<>
<DashboardActions />
<h2 className='my-2'>Education Details</h2>
<table className='table'>
<thead>
<tr>
<th>Level</th>
<th>Field of study</th>
<th>School</th>
</tr>
</thead>
<tbody>{profile.education.map((edu) => console.log(edu))}</tbody>
</table>
</>
)}
</>
)
}
export default Dashboard
Issue
state.profile.educatioin is undefined in your initial state.
export const profileDetailsReducer = (state = { profile: {} }, action) => { ...
Solution(s)
Define an initial state that contains an education array
const initialState = {
profile: {
education: [],
},
};
export const profileDetailsReducer = (state = initialState, action) => { ...
Or provide a fallback value from your selector
const { loading, error, profile: { education = [] } } = profileDetails;
...
<tbody>{education.map((edu) => console.log(edu))}</tbody>
Or provide the fallback in the render
<tbody>{(profile.education ?? []).map((edu) => console.log(edu))}</tbody>

How to modify existing data in reducer?

I'm new to react-redux, I was working on a tutorial and I wanted to add a few features of my own.
How do I add a new method to add a new song to the existing array of song objects > I was confused because theres already a song key in combine reducers. What should I return/pass as a parameter to add a new song?
import { combineReducers } from "redux";
const songsReducer = () => {
return [
{
title: "song one",
duration: "4:30"
},
{
title: "song one",
duration: "4:00"
},
{
title: "song one",
duration: "3:28"
},
{
title: "song one",
duration: "3:50"
}
];
};
const selectedSongReducer = (selectedSong = null, action) => {
if (action.type === "SONG_SELECTED") {
return action.payload;
}
return selectedSong;
};
**const addSong = () => {};** // need help with this function
export default combineReducers({
songs: songsReducer,
selectedSong: selectedSongReducer
});
const addSong = song => ({
type: 'ADD_SONG',
payload: song,
});
const songsReducer = (songs = [], action) => {
switch (action.type) {
case 'ADD_SONG': {
return [...songs, action.payload.song]; //immutable
}
default: {
return [
{
title: 'song one',
duration: '4:30',
},
{
title: 'song one',
duration: '4:00',
},
{
title: 'song one',
duration: '3:28',
},
{
title: 'song one',
duration: '3:50',
},
];
}
}
};
The action will return a song with type ADD_SONG:
const addSong = (song) => {
return {
type: "ADD_SONG",
payload: {
song
}
}
}
In reducer:
const selectedSongReducer = (selectedSong = [], { type, payload = {} }) => {
if (type === "SONG_SELECTED") {
return payload;
}
if (type === "ADD_SONG") {
return [...selectedSong].push(payload.song) // Imutable selectedSong
}
return selectedSong;
};
Always use switch case for cleaner code
and return like this return [...selectedSong, action.payload];
to avoid mutation
const addSong = (song) => {
return {
type: "ADD_SONG",
payload: {
song
}
}
}
const selectedSongReducer = (selectedSong = [], action) => {
switch (action.type) {
case 'SONG_SELECTED': {
return [...selectedSong, action.payload.song];
}
default: null
}
};
const songsReducer = (song = [], action) => {
switch (action.type) {
case 'ADD_SONG': {
return [...songs, action.payload.song];
}
default: {
return [
{
title: 'song one',
duration: '4:30',
},
{
title: 'song one',
duration: '4:00',
},
{
title: 'song one',
duration: '3:28',
},
{
title: 'song one',
duration: '3:50',
},
];
}
}
};

Resources