dispatch thunk return to component - reactjs

I'm trying to pass the response of a dispatched function back to my component code. I get an signed request from my backend then upload the file from my component.
my component code here get's an S3 signature from my backend to upload a file
handleSubmitClick = async () => {
if (this.state.name){
let newFile = {
filename: this.state.name,
filetype: this.state.media.type,
}
this.props.signS3(newFile.filename, newFile.filetype)
.then( res => console.log('NO RESPONSE', res))
this.handleCloseClick();
} else {
this.setState({ inputError: true });
}
}
i get signS3 from mapdispatchtoprops
const mapDispatchToProps = dispatch => {
return {
handleCancelClick() {
dispatch(openAttachAssetModal(false));
},
signS3(filename, filetype) {
dispatch(signS3(filename, filetype));
}
}
}
It runs my mutation
export function signS3(filename, filetype) {
return function thunk(dispatch) {
const client = ApolloClient();
return client.mutate({
variables: { filename, filetype },
mutation: gql`
mutation signS3($filename: String!, $filetype: String!){
signS3(input: {
filename: $filename
filetype: $filetype
}) {
signedRequest
url
}
}
`
})
.then(response => {
return response
})
}
}
except I don't get a response returned...

In mapDispatchToProps you have to return what you're dispatching (in this case a promise) in signS3 otherwise the value will be undefined.
// ...
signS3(filename, filetype) {
return dispatch(signS3(filename, filetype));
}

Related

redux-next-wrapper with supabase v2 ssr

Before supabase V2 I got my data and stored in with redux like this:
supabase V2 broke unfortunately some functionality with redux-next-wrapper
export const getServerSideProps = wrapper.getServerSideProps(
(store) => async ({ req }) => {
const { user } = await supabase.auth.api.getUserByCookie(req);
if (user === null) {
return {
redirect: {
permanent: false,
destination: "/auth",
},
props: {},
};
}
if (user) {
async function getData() {
let { data, error, status } = await supabase
.from("table")
.select(`id`)
.eq("id", user.id);
store.dispatch(writeUserData(data));
return data;
}
return {
props: {
data: await getData(),
},
};
}
}
);
Any ideas how I can achieve the same functionality with withPageAuth()?
export const getServerSideProps = withPageAuth({
redirectTo: '/foo',
async getServerSideProps (ctx, supabase) {
// Access the user object
const {
data: { user }
} = await supabase.auth.getUser()
return { props: { id: user?.id } }
}
})
This would be similar to what you already have except that the redirect is handled by the withPageAuth already.
export const getServerSideProps = withPageAuth({
redirectTo: '/auth',
async getServerSideProps (ctx, supabase) {
// Access the user object
const {
data: { user }
} = await supabase.auth.getUser()
let { data, error, status } = await supabase
.from("table")
.select(`id`)
.eq("id", user.id);
store.dispatch(writeUserData(data));
return { props: { data } }
}
})

React-query: mutation is returning undefined data

Hello I am working with React-Query useMutation()
const { data: createTemplateData, mutate: createTemplate } = useMutation(
mutationService.createTemplate,
{
onSuccess: (newTemplate) => {
return queryClient.invalidateQueries("templates");
},
},
);
the function call looks like
const getMutationService = () => {
return {
createTemplate: async (
formData: CreateTemplateRequest,
): Promise<CreateTemplateResponse | undefined> => {
try {
const result = await templateApi.createTemplate(formData as any);
return result;
} catch (error) {
console.log("Error creating template", error);
}
},
};
};
I am able to mutate successfully (POST API Request) however, the data | createTemplateData is returning undefined after successful network request

How to make a PATCH request in ReactJS ? (with Nestjs)

nestjs controller.ts
#Patch(':id')
async updateProduct(
#Param('id') addrId: string,
#Body('billingAddr') addrBilling: boolean,
#Body('shippingAddr') addrShipping: boolean,
) {
await this.addrService.updateProduct(addrId, addrBilling, addrShipping);
return null;
}
nestjs service.ts
async updateProduct(
addressId: string,
addrBilling: boolean,
addrShipping: boolean,
) {
const updatedProduct = await this.findAddress(addressId);
if (addrBilling) {
updatedProduct.billingAddr = addrBilling;
}
if (addrShipping) {
updatedProduct.shippingAddr = addrShipping;
}
updatedProduct.save();
}
there is no problem here. I can patch in localhost:8000/address/addressid in postman and change billingAddr to true or false.the backend is working properly.
how can i call react with axios?
page.js
const ChangeBillingAddress = async (param,param2) => {
try {
await authService.setBilling(param,param2).then(
() => {
window.location.reload();
},
(error) => {
console.log(error);
}
);
}
catch (err) {
console.log(err);
}
}
return....
<Button size='sm' variant={data.billingAddr === true ? ("outline-secondary") : ("info")} onClick={() => ChangeBillingAddress (data._id,data.billingAddr)}>
auth.service.js
const setBilling = async (param,param2) => {
let adressid = `${param}`;
const url = `http://localhost:8001/address/`+ adressid ;
return axios.patch(url,param, param2).then((response) => {
if (response.data.token) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
}
I have to make sure the parameters are the billlingddress field and change it to true.
I can't make any changes when react button click
Since patch method is working fine in postman, and server is also working fine, here's a tip for frontend debugging
Hard code url id and replace param with hard coded values too:
const setBilling = async (param,param2) => {
// let adressid = `${param}`;
const url = `http://localhost:8001/address/123`; // hard code a addressid
return axios.patch(url,param, param2).then((response) => { // hard code params too
console.log(response); // see console result
if (response.data.token) {
// localStorage.setItem("user", JSON.stringify(response.data));
}
// return response.data;
})
}
now it worked correctly
#Patch('/:id')
async updateProduct(
#Param('id') addrId: string,
#Body('billingAddr') addrBilling: boolean,
) {
await this.addrService.updateProduct(addrId, addrBilling);
return null;
}
const ChangeBillingAddress = async (param) => {
try {
await authService.setBilling(param,true).then(
() => {
window.location.reload();
},
(error) => {
console.log(error);
}
);
}
catch (err) {
console.log(err);
}
}
const setBilling= async (param,param2) => {
let id = `${param}`;
const url = `http://localhost:8001/address/`+ id;
return axios.patch(url,{billingAddr: param2}).then((response) => {
if (response.data.token) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
}

Dispatch multiples http request React/Redux

I'm trying to dispatch more than one axios request inside my method. However, it is not working.
export const getImages = (res) => {
return {
type: actionTypes.GET_IMAGES,
payload: res
}
}
export const loadImages = (imgs, cId) => {
return dispatch => {
let data = [];
for(const i of imgs) {
const id = i.id;
axios.get(`${api.URL}/test/${cId}/files/${id}`)
.then(res => {
if(res.data !== -1) {
const obj = {
name: res.data,
desc: i.caption
};
data(obj);
}
//dispatch(getImages(data));
});
}
console.log('Action:');
console.log(data);
dispatch(getImages(data));
}
}
The console log does not print anything. Do I need to dispatch inside the .then()? If so, how can I run multiples requests before dispatching?
Thanks

how to async/await redux-thunk actions?

action.js
export function getLoginStatus() {
return async(dispatch) => {
let token = await getOAuthToken();
let success = await verifyToken(token);
if (success == true) {
dispatch(loginStatus(success));
} else {
console.log("Success: False");
console.log("Token mismatch");
}
return success;
}
}
component.js
componentDidMount() {
this.props.dispatch(splashAction.getLoginStatus())
.then((success) => {
if (success == true) {
Actions.counter()
} else {
console.log("Login not successfull");
}
});
}
However, when I write component.js code with async/await like below I get this error:
Possible Unhandled Promise Rejection (id: 0): undefined is not a function (evaluating 'this.props.dispatch(splashAction.getLoginStatus())')
component.js
async componentDidMount() {
let success = await this.props.dispatch(splashAction.getLoginStatus());
if (success == true) {
Actions.counter()
} else {
console.log("Login not successfull");
}
}
How do I await a getLoginStatus() and then execute the rest of the statements?
Everything works quite well when using .then(). I doubt something is missing in my async/await implementation. trying to figure that out.
The Promise approach
export default function createUser(params) {
const request = axios.post('http://www...', params);
return (dispatch) => {
function onSuccess(success) {
dispatch({ type: CREATE_USER, payload: success });
return success;
}
function onError(error) {
dispatch({ type: ERROR_GENERATED, error });
return error;
}
request.then(success => onSuccess, error => onError);
};
}
The async/await approach
export default function createUser(params) {
return async dispatch => {
function onSuccess(success) {
dispatch({ type: CREATE_USER, payload: success });
return success;
}
function onError(error) {
dispatch({ type: ERROR_GENERATED, error });
return error;
}
try {
const success = await axios.post('http://www...', params);
return onSuccess(success);
} catch (error) {
return onError(error);
}
}
}
Referenced from the Medium post explaining Redux with async/await: https://medium.com/#kkomaz/react-to-async-await-553c43f243e2
Remixing Aspen's answer.
import axios from 'axios'
import * as types from './types'
export function fetchUsers () {
return async dispatch => {
try {
const users = await axios
.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => res.data)
dispatch({
type: types.FETCH_USERS,
payload: users,
})
} catch (err) {
dispatch({
type: types.UPDATE_ERRORS,
payload: [
{
code: 735,
message: err.message,
},
],
})
}
}
}
import * as types from '../actions/types'
const initialErrorsState = []
export default (state = initialErrorsState, { type, payload }) => {
switch (type) {
case types.UPDATE_ERRORS:
return payload.map(error => {
return {
code: error.code,
message: error.message,
}
})
default:
return state
}
}
This will allow you to specify an array of errors unique to an action.
Another remix for async await redux/thunk. I just find this a bit more maintainable and readable when coding a Thunk (a function that wraps an expression to delay its evaluation ~ redux-thunk )
actions.js
import axios from 'axios'
export const FETCHING_DATA = 'FETCHING_DATA'
export const SET_SOME_DATA = 'SET_SOME_DATA'
export const myAction = url => {
return dispatch => {
dispatch({
type: FETCHING_DATA,
fetching: true
})
getSomeAsyncData(dispatch, url)
}
}
async function getSomeAsyncData(dispatch, url) {
try {
const data = await axios.get(url).then(res => res.data)
dispatch({
type: SET_SOME_DATA,
data: data
})
} catch (err) {
dispatch({
type: SET_SOME_DATA,
data: null
})
}
dispatch({
type: FETCHING_DATA,
fetching: false
})
}
reducers.js
import { FETCHING_DATA, SET_SOME_DATA } from './actions'
export const fetching = (state = null, action) => {
switch (action.type) {
case FETCHING_DATA:
return action.fetching
default:
return state
}
}
export const data = (state = null, action) => {
switch (action.type) {
case SET_SOME_DATA:
return action.data
default:
return state
}
}
Possible Unhandled Promise Rejection
Seems like you're missing the .catch(error => {}); on your promise. Try this:
componentDidMount() {
this.props.dispatch(splashAction.getLoginStatus())
.then((success) => {
if (success == true) {
Actions.counter()
} else {
console.log("Login not successfull");
}
})
.catch(err => {
console.error(err.getMessage());
}) ;
}
use dispatch(this.props.splashAction.getLoginStatus()) instead this.props.dispatch(splashAction.getLoginStatus())

Resources