How do you pass arguments to createAsyncThunk in redux toolkit? - javascript

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

Related

How to map this given api response in react js javascript

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();
}, []);

dispatching Asynchronous action from an array react redux thunk

As per the requirement we need to make API call from the array list.Have used redux-thunk for async operation.Having issues while passing the request parameter to the reducer after api call is finished.
# From the container
let document = [ bankstatement1,bankstatement2];
document.map(element => {
dispatch ( actions.uploadFiles(element) )
});
# inside actions
export const uploadFiles = (payload) => {
return async dispatch => {
const response = await callAPIMiddleware(dispatch, {
types: ['DOC_UPLOAD_START','DOC_UPLOAD_SUCCESS','DOC_UPLOAD_ERROR'],
endPoint: ApiEndpoints.DOCUMENT_UPLOAD,
type: HTTP_METHOD_TYPE.POST,
payload: payload,
headers: Headers.multipart,
});
return response;
};
};
# inside axios middle ware
export const callAPIMiddleware = async (dispatch, RequestParams) => {
# calling upload_start ,here also the request payload being asked.
dispatch({
type: "DOC_UPLOAD_START,
data:RequestParams //bankstatement1,bankstatement2
});
# let res = await axios.post(endPoint,RequestParams, {
headers: reqHeaders,
config: reqConfig,
});
if (res && res.data) {
dispatch({
type:'DOC_UPLOAD_SUCCESS',
data: res.data,
param:RequestParams //bankstatement2,bankstatement2 here it is always referring to "bankstatement2"
});
}
After the API call is finished, reference to first request parameter is overridden by second one.Can anyone suggest how we can still refer to the first element .
EDITED:
what if you try to place the last piece of logic in "then" so it surely scoped there?
axios.post(endPoint,RequestParams, {
headers: reqHeaders,
config: reqConfig,
}).then(res => {
console.log('calling dispatch for ', RequestParams);
if (res && res.data) {
dispatch({
type:'DOC_UPLOAD_SUCCESS',
data: res.data,
param: RequestParams,
});
} else {
console.log('oops no result for ', RequestParams);
}
})

TypeError: can't access property "error", data is undefined

got the title error and can't fix it :(. I'm triying to get the data from a signup page, here is my javascript code:
const SignupComponent = () => {
const [values, setValues] = useState({
name: 'ryan',
email: 'ryan#gmail.com',
password: 'rrrrrr',
error: '',
loading: false,
message: '',
showForm: true
});
const { name, email, password, error, loading, message, showForm } = values;
const handleSubmit = e => {
e.preventDefault();
// console.table({ name, email, password, error, loading, message, showForm });
setValues({ ...values, loading: true, error: false });
const user = { name, email, password };
signup(user).then(data => {
if(data.error) {
setValues({ ...values, error: data.error, loading: false });
} else {
setValues ({ ...values, name: '', email: '', password: '', error: '', loading: false, message: data.message, showForm: false});
}
});
};
const handleChange = name => e => {
setValues({ ...values, error: false, [name]: e.target.value })
, so when i try to register in the page, its says TypeError: can't access property "error", data is undefined.
signup(user).then(data => {
> 25 | if(data.error) {
| ^
26 | setValues({ ...values, error: data.error, loading: false });
27 | } else {
Signup Function
export const signup = (user) => {
return
fetch(${API}/signup, { method: 'POST',
headers: { Accept: 'application/json',
'Content-Type': 'application/json' },
body: JSON.stringify(user) })
.then(response => { return response.json(); })
.catch(err => console.log(err));
i'm kinda nooby in programming but i already look in the internet for a solution, nothing works u.U
I guess you are not quite familiar with the concept of Asynchronous programming. Fetch is an Async function and if you want to wait for it's output you have to you use the Await keyword which also requires signup to be Async. So your code will look some what like this:
export const signup = async (user) => {
let fetchResponse = fetch(${API}/signup, { method: 'POST',
headers: { Accept: 'application/json',
'Content-Type': 'application/json' },
body: JSON.stringify(user) });
return (await fetchResponse.json())
To Learn more about Asynchronous programming, I recommend reading this article https://blog.risingstack.com/node-hero-async-programming-in-node-js/
When you called json() method in fetch response a Promise is returned since reading a stream object will happen aysnchronously. So what you is to chain another then function to get that data like this.
export const signup = user => {
return fetch(`${API}/signup`, {
method: "POST",
headers: { Accept: "application/json", "Content-Type": "application/json" },
body: JSON.stringify(user)
})
.then(response => {
return response.json();
})
.then(data => {
return data;
})
.catch(err => console.log(err));
};
PS: neither you need to use async/ await since you are using Promises with .then(), nor there is any need for chaining with one more .then() inside signup() since you are already doing that in handleSubmit() where you've called signup().
Try re-writing your signup() function as below. I guess you've missed back-ticks because I've implemented the SignUp in a similar way and it works for me. Let me know if it helps:
export const signup = (user) => {
return fetch(`${API}/signup`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(user)
})
.then(response => {
return response.json();
})
.catch(err => console.log(err));
PS: neither you need to use async/await since you are using Promises with .then(), nor there is any need for chaining with one more .then() inside signup() since you are already doing that in handleSubmit() where you've called signup().

I can't get this React action's return statement to run

The following code is a React action that is supposed to dispatch to a reducer. I can't seem to get the return statement to run. I can get it to hit a debugger right blelow the data variable declaration, but that's it. If I try to run the rest of the code within debugger, I'm getting a reference error "Return is not a function". I can't figure out what I'm missing here. Any help would be greatly appreciated. Thanks in advance.
const baseUrl = 'http://localhost:3001'
export const signUp = (user) => {
let data = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ user })
}
return dispatch => {
fetch(`${ baseUrl }/signup`, data)
.then(response => response.json())
.then(user => {
sessionStorage.setItem('user', user)
dispatch({
type: 'SET_USER',
payload: user.current
})
})
.catch(err => err)
}
}
Well if you are using redux-thunk you are missing the parameters inside for your function and currently you have just user. Try this:
export const signUp = (dispatch, getState, user) => {
...your code
}

Unhandled rejection when importing string constants rather than declaring them locally

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

Categories

Resources