I have a React-Redux thunk action that retrieves categories from an API server then adds them to the Redux store:
(categoryActions.js)
export const fetchCategories = () => dispatch => (
CategoryAPI.getCategories().then(categories => {
for(const category of categories) {
const {name, path} = category
dispatch(addNewCategory(name,path))
}
})
)
It works fine when using it with the following API call:
(categoryApi.js)
const apiServerURL = "http://localhost:3001"
const headers = {
'Content-Type': 'application/json',
'Authorization': 'whatever-you-want'
}
export const getCategories = () => (
fetch(`${apiServerURL}/categories`, { headers })
.then(res => res.json())
.then(data => data.categories)
)
However, when I try to define the API constants in a different file like so:
(apiConstants.js)
export const HEADERS = {
'Content-Type': 'application/json',
'Authorization': 'whatever-you-want'
}
export const SERVER_URL = "http://localhost:3001"
and then use them in categoryApi.js:
import {
HEADERS,
SERVER_URL
} from './apiConstants'
export const getCategories = () => (
fetch(`${SERVER_URL}/categories`, { HEADERS })
.then(res => res.json())
.then(data => data.categories)
)
I get the following error from line 3 of the thunk action in categoryActions.js above:
Unhandled Rejection (TypeError): Cannot read property
'Symbol(Symbol.iterator)' of undefined
What's the problem?
The problem is your variable is capitalized, so you need to set the property correctly, because fetch expects it lowercase:
export const getCategories = () => (
fetch(`${SERVER_URL}/categories`, { headers: HEADERS })
.then(res => res.json())
.then(data => data.categories)
)
--
{ headers }
is equivalent to:
{ headers: headers }
So in your second example you have it capitalized:
{ HEADERS: HEADERS }
This is known as property shorthand
Related
I want to create new folder name services in that folder will include all axios action and I'm using vue here. Heres what I try..
my save function
save() {
const CaseController = require("../services/gantt");
CaseController.create(this.data);
},
my service file
const axios = () => import("../plugins/axios");
exports.create = async () => {
return axios
.get("/")
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
})
.finally(() => {});
};
my plugins file
import axios from "axios";
export default axios.create({
baseURL: process.env.VUE_APP_API_URL,
headers: {
"Content-Type": "application/json",
},
});
but when I try, I got an error
Uncaught (in promise) TypeError: axios.get is not a function
Well, you've defined axios as () => import("../plugins/axios");, so it's a function, which does not have a .get method. Further, using import as a function makes it return a promise. You need to do:
const axios = import("../plugins/axios");
exports.create = async () => {
return (await axios)
.get("/")
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
})
.finally(() => {});
};
i solve this with
const axios = require("axios");
const instance = axios.create({
baseURL: process.env.VUE_APP_API_URL,
headers: {
"Content-Type": "application/json",
},
});
exports.create = async () => {
instance
.get("/")
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
})
.finally(() => {});
};
so, instead import the axios from plugins folder, use it directly from services
I am getting an error when i was calling an post request in use effect hook and i got the response as promise pending, but the object is there, please see the response and please provide a perfect code to map this response.
code
function Comment({ id }) {
const [data, setdata] = useState([]);
console.log(id);
useEffect(() => {
const query = `
query{
forumAnswerId(id:${id}){
forumAnswerBody
forumAnswerTime
forumAnswerCode1
forumAnswerCode2
forumAnswerCode3
forumAnswerAuthor
forumAnswerBoolean
forumAnswerCode1Title
forumAnswerCode2Title
forumAnswerCode3Title
}
forumComment(forumAnswerComment:${id}){
forumAnswerCommentPost
forumAnswerCommentBody
forumAnswerCommentAuthor
forumAnswerCommentTime
}
}
`;
const opts = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query }),
};
const res = fetch('http://127.0.0.1:8000', opts).then((res) => res.json());
setdata(res);
}, []);
return <div></div>;
}
export default Comment;
here you are:
fetch('http://127.0.0.1:8000', opts)
.then((res) => res.json())
.then(r=> setdata(r))
promise result cannot be accessed outside. You need to set data inside the then function
Using Promise
fetch('http://127.0.0.1:8000', opts).then((res) => setdata(res.json()));
Using Async await
const res=await fetch('http://127.0.0.1:8000', opts)
setdata(res.json())
useEffect(() => {
const fetchData = async () => {
const query = `
query{
forumAnswerId(id:${id}){
forumAnswerBody
forumAnswerTime
forumAnswerCode1
forumAnswerCode2
forumAnswerCode3
forumAnswerAuthor
forumAnswerBoolean
forumAnswerCode1Title
forumAnswerCode2Title
forumAnswerCode3Title
}
forumComment(forumAnswerComment:${id}){
forumAnswerCommentPost
forumAnswerCommentBody
forumAnswerCommentAuthor
forumAnswerCommentTime
}
};`
const opts = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query }),
};
const res = await fetch('http://127.0.0.1:8000', opts).then((res) => res.json());
setdata(res);
}
fetchData();
}, []);
I'm trying to figure out how to code my current API call so that I can access each field from the API call and render it, then be able to use it across multiple components. I'm using the QuickBase API call that only allows POST to pull field values. I've been out of the game for a couple of years and can't figure out how to accurately render these to be able to be used in other components by importing the api.js file. The project is a React within Electron to pull QuickBase data, and be able to create Line Charts (7 on one page) to show a job cost/hours and the jobs included departments cost/hours. All of my data is in quickbase, I just can't figure out how to get it over to react and able to actually use it!
Here is my API call:
let headers = {
'QB-Realm-Hostname': 'XXXXXXXXX.quickbase.com',
'User-Agent': 'FileService_Integration_V2.1',
'Authorization': 'QB-USER-TOKEN XXXXXX_XXXXX_XXXXXXXXXXXXXXX',
'Content-Type': 'application/json'
}
let body = {"from":"bpz99ram7","select":[3,6,80,81,82,83,86,84,88,89,90,91,92,93,94,95,96,97,98,99,101,103,104,105,106,107,109,111,113,115,120,123,224,225,226,227,228,229,230,231,477,479,480,481],"sortBy":[{"fieldId":6,"order":"ASC"}],"groupBy":[{"fieldId":40,"grouping":"equal-values"}],"options":{"skip":0,"top":0,"compareWithAppLocalTime":false}}
fetch('https://api.quickbase.com/v1/records/query',
{
method: 'POST',
headers: headers,
body: JSON.stringify(body)
})
.then(res => {
if (res.ok) {
return res.json().then(res => console.log(res));
}
return res.json().then(resBody => Promise.reject({status: res.status, ...resBody}));
})
.catch(err => console.log(err))
Any help would be greatly appreciated as I've been struggling on this for awhile! Right now I'm able to get all the correct data in the Console. But don't know how to go about rendering it on my application for actual use.
Thanks!
I think you should put your code inside a function and call that function from the component where you need the data, something like
import React, { Component } from 'react'
let headers = {
'QB-Realm-Hostname': 'XXXXXXXXX.quickbase.com',
'User-Agent': 'FileService_Integration_V2.1',
'Authorization': 'QB-USER-TOKEN XXXXXX_XXXXX_XXXXXXXXXXXXXXX',
'Content-Type': 'application/json'
};
class App extends Component {
state = {
data: null,
}
componentDidMount() {
this.fetchData();
}
fetchData = () => {
let body = {"from":"bpz99ram7","select":[3,6,80,81,82,83,86,84,88,89,90,91,92,93,94,95,96,97,98,99,101,103,104,105,106,107,109,111,113,115,120,123,224,225,226,227,228,229,230,231,477,479,480,481],"sortBy":[{"fieldId":6,"order":"ASC"}],"groupBy":[{"fieldId":40,"grouping":"equal-values"}],"options":{"skip":0,"top":0,"compareWithAppLocalTime":false}}
fetch('https://api.quickbase.com/v1/records/query', {
method: 'POST',
headers: headers,
body: JSON.stringify(body)
}).then(response => {
if (response.ok) {
return response.json().then(res => {
this.setState({
data: res,
})
});
}
return response.json().then(resBody => Promise.reject({status: response.status, ...resBody}));
}).catch(err => console.log(err))
}
render() {
const { data } = this.state;
if (data === null) return 'Loading...';
return (
<div>
{/* Do something with data */}
</div>
);
}
}
export default App;
Check the Docs, you can send the JSON in the props of the component to render it.
You can modify your code following this example.
sandbox
import { useEffect, useState } from "react";
async function apiCall() {
return await new Promise((resolve, reject) => {
// Api Call
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => resolve(json));
});
}
const TestApp = () => {
let [data, setData] = useState({ Text: "Before api call." });
useEffect(() => {
(async () => {
let res = await apiCall();
res.Text = "After api call.";
setData(res);
})();
}, []);
return (
<div>
UserId: {data.userId} id: {data.id} title: {data.title}{" "}
completed: {data.completed}
</div>
);
};
module.exports = TestApp;
So i'm new to redux-toolkit and I want to do something really simple. I want to send some data on a POST request via this helper function. so I tried this
export const submitPaymentToServer = createAsyncThunk(
'data/fetchAll',
async ({ name, data }) => {
return fetch('/payments', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name,
data,
}),
})
.then((res) => res.json())
.then((res) => res)
},
)
but when I call it like so
dispatch(
submitPaymentToServer({
name,
data,
}),
)
typescript complains saying I don't have the right number of arguments. so how am I suppose to pass args to this function? or what is the way to do this with toolkit?
This is what React-Redux says when you are using createAsyncThunk
You can only pass one argument to the thunk when you dispatch it. If you need to pass multiple values, pass them in a single object
So instead of
export const submitPaymentToServer = createAsyncThunk(
'data/fetchAll',
async ({ name, data }) => { // here you have two arguments
return fetch('/payments', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name,
data,
}),
})
.then((res) => res.json())
.then((res) => res)
},
)
You can only have one argument:
export const submitPaymentToServer = createAsyncThunk(
'data/fetchAll',
async (yourData) => {
const {name, data} = yourData;
return fetch('/payments', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name,
data,
}),
})
.then((res) => res.json())
.then((res) => res)
},
)
Destructure your object inside the thunk call.
Reference: here
You need to actually give these arguments a type:
export const submitPaymentToServer = createAsyncThunk(
'data/fetchAll',
async ({ name, data }: { name: string, data: MyDataType }) => {
return fetch('/payments', {
If you are using JavaScript with TypeScript only in the IDE, you can add a docblock for that:
const thunk2 = createAsyncThunk(
'data/fetchAll',
/** #param arg {{ name: string, data: MyDataType }} */
(arg) => {
return fetch('/payments', {
I found this in the TypeScript Redux documentation
const fetchUserById = createAsyncThunk<
// Return type of the payload creator
MyData,
// First argument to the payload creator
number
>('users/fetchById', async (userId, thunkApi) => {
const response = await fetch(`https://reqres.in/api/users/${userId}`, {
headers: {
Authorization: `Bearer ${thunkApi.extra.jwt}`,
},
})
return (await response.json()) as MyData
})
The argument passed into createAsyncThunk is userId which I've defined with type number.
If you are using typescript, consider adding createAsyncThunk() types according to docs. to see if this works for you add:
createAsyncThunk
<any, any, any>(...)
and don't forget to use proper typing based on:
https://redux-toolkit.js.org/api/createAsyncThunk
I am trying to login using react and django rest.
I have rest-auth for the login backend and users are coming from a LDAP.
The login on django works.
Also the response from my backend works too when calling from react.
I tried to save my token in a cookie using react-cookie.
But when I do, I have the error : TypeError: Cannot read property 'token' of undefined
I split my code. I have a file api_auth_service.js
export class APILogin {
static loginUser(body){
return fetch('http://127.0.0.1:8000/rest-auth/login/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
}).then( resp => resp.json())
}
}
and my login view in react :
export default function Login() {
const [ username, setUsername] = useState('');
const [ password, setPassword] = useState('');
const [token, setToken] = useCookies(['gra-token']);
useEffect(() => {
console.log(token);
}, [token])
const loginClicked = () => {
APILogin.loginUser({username, password})
.then( resp => console.log(resp))
.then(resp => setToken('gra-token', resp.token))
.catch( error => console.log(error))
}
return ( .............
And what is saved into my cookie is not the token obviously as you can see
const loginClicked = () => {
APILogin.loginUser({username, password})
.then( resp => resp)
.then(resp => setToken('gra-token', resp.token))
.catch( error => console.log(error))
}
You need to return the resp from the first then statement