Download file using redux flow - javascript

Could not find any example describing it.
I'm trying to create download button using react app but going through redux, ie. in action I'm connecting to url and getting the file in response (code 200).
export function sendTimeline(token, timelineObj) {
const request = axios.post(`muURLGoesHere`, timelineObj, {
headers: {
"Content-Type": "application/vnd.ms-excel",
"X-Accept-Version": "v1",
Authorization: `Bearer ${token}`
}
});
console.log(request);
return {
type: constants.actionTypes.TIMELINE_DATA,
payload: request
};
}
How can I pass it to reducer and download it on the react side.
You maybe know the article with an example or any hint on that.
Thank you

I wouldn't dispatch actions with promised as payload. Use redux-thunk additionally to do more fine grained dispatch of successive actions:
const sendTimeline = (token, timline) => dispatch => {
dispatch({ type: 'sendtimeline/start' })
return fetch(…)
.then(res => res.json())
.then(json => dispatch({
type: 'sendtimeline/success',
payload: json
}))
.catch(err => dispatch({
type: 'sendtimeline/error',
payload: err,
error: true
}))
}
That way you do not have to deal with async problems in the reducer, since the actions handle that. Also you can do stuff like:
this.props.sendTimeline(…).then(…)
when used within a component, since the promise is returned from the action creator.
Have a look here as well

Related

how can I test this redux action in jest?

I want to test this redux action which uses axios, I have succesfully tested the success path but I can't reach the catch block to complete the code coverage. I'm mocking axios using a mocks folder in jest.
export const fetchTasks = () => dispatch => {
dispatch(fetchLoading());
axios
.get(url + '/all', { mode: 'cors' })
.then(response => {
dispatch(setTasks(response.data));
dispatch(fetchDone());
})
.catch(response => {
console.log(response);
dispatch(fetchDone());
});
};
this is my success path test which implements a redux store and expects loading and setTasks to run and the setTasks action to have a payload that matches my mockObjects tasks list.
describe('when fetchTasks is dispatched', () => {
it('should dispatch other actions with correct payloads', async () => {
const store = testStore();
const spyOnDispatch = jest.spyOn(store, 'dispatch');
await tasksActions.fetchTasks()(store.dispatch, store.getState);
expect(spyOnDispatch).toHaveBeenCalledWith({ type: 'FETCH_LOADING' });
expect(spyOnDispatch).toHaveBeenCalledWith({ type: 'SET_TASKS', tasks: mockObjects.mockTasks });
expect(spyOnDispatch).toHaveBeenCalledWith({ type: 'FETCH_DONE' });
expect(store.getState().tasksState.tasks).toEqual(mockObjects.mockTasks);
});
});
I've tried to use this code to make the catch code to run but it executes the same code as the success path and sets the tasks list to undefined
mockAxios.get.mockImplementationOnce(() => Promise.reject({ status: 400 }));
When testing frontend code that makes HTTP request, I suggest using a mocking library to create fake responses. Two that I am familar with are nock and fetch-mock. You should be able to throw an error in your mock response code so that it triggers the catch() branch.

How to fix "undefined" issue in async call to dispatch in action creator of redux?

I'm making a react app, implementing authentication to get token for the provides credentials from the server using the API call. Do my approach is perfect to do this?
I'm using Django API for backend and reactJS for frontend also using thunk as a middleware with redux.
authAction.js
import {AUTH_USER} from "./types";
export const authUser = (username, password) =>
{
return (dispatch) => {
const data = {
username: username,
password: password
}
return fetch("http://127.0.0.1:8000/api/v1/login/auth/", {
method: 'POST',
body: JSON.stringify(data),
headers: {'Content-Type': 'application/json'}
})
.then(results => results.json())
.then(results => {
dispatch({
type: AUTH_USER,
payload: results
})
}
)
}
}
authReducer.js
import {AUTH_USER} from "../actions/types";
const initialState = {
errors: [],
token : '',
}
export default function (state=initialState,action) {
switch (action.type) {
case AUTH_USER:
return {
...state,
token:action.payload.token,
errors:action.payload.errors,
}
default:
return state
}
}
login function
login(e){
e.preventDefault();
if(this.state.username && this.state.password){
console.log("Login");
this.props.authUser(this.state.username,this.state.password)
.then(res=>console.log(res)) // undefined
}
}
I want to get the results to be printed on the console which is fetched from API or in the more explained way I want to return the fetched results from the call of action in the caller. i.e. token: any token
It doesn't work that way. When you perform the action, after the async call, you do a dispatch with the result and the result is added to the store through the reducer. You need to get the values from the store by connecting to the store.
const mapStateToProps = ({
token, errors
}) => ({
token,
errors
});
connect(mapStateToProps, {authUser})(Login)
You can access this in your component now using this.props.token & this.props.errors

How to correctly manage fetch errors response with observables and RxJS?

I just recovered a simple auth app built with ReactJS, redux-observable and RxJS.
I want to implement an error handler when the API backend send a response > 400.
Actually, there is an epic that handle login process on LOGIN_REQUEST event:
const apiLoginEpic = (action$, state$) =>
action$.pipe(
ofType(authConstant.LOGIN_REQUEST),
mergeMap(action => authService.loginApi(action.username, action.password)),
map(({ body }) => extractJwtPayload(body.token)),
map(authAction.login.apiSuccess),
logObservableErrorAndTriggerAction(authAction.login.apiFailure)
This epic just call a service, which is a simple fetch that refer to:
const fetchBackend = (path, options = {}, withCredentials = false) => {
fetch(`${process.env.REACT_APP_BACKEND_URL}${path}`, options)
.then(response =>
response.status < 400
? Promise.all([response, response.json()])
: Promise.reject(response)
)
.then(([response, body]) => ({
status: response.status,
headers: response.headers,
body,
}))
}
As you can see, when the response status is superior to 400, it reject the promise. Then, in the epic (first code extract), the error is catch in logObservableErrorAndTriggerAction function which is implemented as:
const logObservableErrorAndTriggerAction = action =>
catchError((response, source) =>
pipe(
tap(logger.error),
() => of(action(response)).pipe(merge(source))
)(response)
)
My problem is that I want to catch the response body in logObservableErrorAndTriggerAction, which can be reusable.
Unfortunately, I don't have much knowledge about observalbes and RxJS.
When I try to use body of the response, it appears that it is a ReadableStream. I tried a lot of things but I can't turn it into JSON :
{
body: ReadableStream,
bodyUsed: false,
headers: Headers {},
ok: false,
redirected: false,
status: 400,
statusText: "",
type: "cors",
url: "http://localhost/api/login"
}
Does anybody know how to manage my use case ?
Thank you very much,
Sylvain

Get API response from redux store and send response

What i want to execute is do a post request and access the res.json() and taking res.json() i want to dispatch a action to update the store and access response object in the component.A small code example will be great.
export const filesDownload = (postData) => dispatch =>{
console.log(postData);
fetch('http://'+ip+':8000/api/v1/integrator/email/need_attachment/',{
method:'POST',
headers: {
'content-type': 'application/json'
},
body : JSON.stringify(postData)
})
.then(res => console.log(res.json()))
.then(files => dispatch({
type: GET_FILES,
payload:files
}))
}
I want to dispatch the res.json() to the store .
Try axios its cleaner:
export const filesDownload = (postData) => dispatch =>{
console.log(postData);
axios.post('http://'+ip+':8000/api/v1/integrator/email/need_attachment/')
.then((response)=>response.data)
.then((files)=>dispatch({
type: GET_FILES,
payload:files
}))
.catch((err)=>console.log(err))
}
If it's not working, you will have to use redux Thunk, tell me, I will help you

Redux thunk. reading data from local

I would like to read the data from customData.json, through the code below but here it requires a url, although i would like to read it locally instead, is it possible to do this?
var customData = require('./customData.json');
export function fetchQuestions() {
return dispatch => {
fetch(customData, {
method: 'get',
headers: {
'Accept': 'application/json',
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
}
})
.then(payload => payload.json())
.then(payload => payload.results)
.then(payload =>
dispatch({
type: 'FETCH_QUESTIONS',
payload: payload
})
)
}
}
If you want to read a JSON from localStorage instead of making a network request every time, it's pretty simple, there's nothing async involved. Assuming you've put it into localStorage.customData:
export function fetchQuestions() {
return dispatch => {
const payload = JSON.parse(localStorage.customData);
dispatch({
type: 'FETCH_QUESTIONS',
payload: payload.results,
});
}
}
Though, unless you're doing something else with it, it would be nicer to save the .results property only onto the disk, rather than the whole payload, since you're not using the rest of it.

Categories

Resources