Redux thunk. reading data from local - javascript

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.

Related

Reading token from AsyncStorage before a fetch call

In my ReactNative app, I'm trying to come up with a nice pattern to read the access_token I store in AsyncStorage and use it in a fetch call.
In other words, I want to create a pattern that uses some type of wrapper that makes sure that the fetch call always has the access_token it needs. So execution order should always be:
Invoke Fetch Call -> Get Token from AsyncStorage and Prep Header -> Execute Fetch Call
I came up with the following code but it looks like I'm having problems with the Async part of AsyncStorage and my fetch calls are going out without the token.
Here's my fetch call:
export const someApiCall = (request) => {
const url = 'https://myapi.com/add';
return (dispatch) => fetch(url, fetchOptionsPost(request))
.then((response) => {
if (response.ok && response.status === 200) {
// Got data. Dispatch some action
}
})
}
Here, I'm using a helper function to prepare the headers, etc. Here's what the fetchOptionsPost() looks like:
export const fetchOptionsPost = (request) => {
getAccessToken()
.then(token => {
return {
method: 'POST',
mode: 'cors',
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + token
},
body: JSON.stringify(request)
}
});
};
And the getAccessToken() function simply reads it from AsyncStorage as below:
export const getAccessToken = async () => {
return await AsyncStorage.getItem("access_token");
}
This pattern is NOT working and API calls are going out without a token.
I also want to mention that if I hard-code the token inside my fetchOptionsPost() method, everything works fine. Clearly, the issue here is that the fetchOptionsPost() is not returning anything.
What can I do to make sure that I will ALWAYS have my token in my fetchOptionsPost?
you could add token call inside someApiCall function .And also create the options on inside the function . function was async so fetch only run after get token result
Updated
const fetchOptionsPost = (token) =>{
return ({
method: 'POST',
mode: 'cors',
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + token
}
})
}
export const someApiCall = async(request) => {
const token = await AsyncStorage.getItem("access_token");
const url = 'https://myapi.com/add';
fetch(url, fetchOptionsPost(token))
.then(response=>response.json())
.then((data)=>{
// call the dispatch here
})
}
Why use async inside on main function
AsyncStorage only have async callback. if you are set the AsyncStorage as separate function you should call async for the both function.Thats why i added with in parent async function and pass the token to fetchOptionsPost
Here's what I've come up with which seems to work fine. I still would appreciate any suggestions or improvements to this code.
First, here's what my fetch call looks like now. I wrapped it inside the getAccessToken() function which is an async call but because I'm using redux-thunk, I'm able to do this.
export const someApiCall = (request) => {
const url = 'https://myapi.com/add';
return (dispatch) => getAccessToken()
.then(token => {
fetch(url, fetchOptionsPost(request, token))
.then((response) => {
if (response.ok && response.status === 200) {
// Got data. Dispatch some action
}
})
})
}
I slightly changed my fetchOptionsPost() helper function which now accepts the token. It's also a bit more robust now. If it doesn't get a token, it simply omits the Authorization part in the header. I opted for this approach as some calls to my API backend do not require authentication. Also the isValidString() is another helper validation function I created to make sure I do get a valid string. It returns a TRUE or FALSE response based on the string value inputed:
export const fetchOptionsPost = (data, token = null) => {
if (isValidString(token)) {
return {
method: 'POST',
mode: 'cors',
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + token
},
body: JSON.stringify(data)
}
} else {
return {
method: 'POST',
mode: 'cors',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
}
}
};
And finally, the getAccessToken() function which didn't really change but here it is:
export const getAccessToken = async () => {
return await AsyncStorage.getItem("access_token");
}
As I said, I'd appreciate any comments or suggestions on further improving this code.
Hope this is useful to others.
Use Async and await method and get the token before each call.
async ()=>{
let token =await getTokenFromLocal();
return (dispatch) => fetch(url, fetchOptionsPost(request))
.then((response) => {
if (response.ok && response.status === 200) {
// Got data. Dispatch some action
}
})
}

How to update data in ReactJS using JSON server

I am new to react and I can fetch the data from JSON file . Now I need to update those values and submit to the JSON file . I am struggling to submit updated input field in JSON file
submitEmpData(event) {
event.preventDefault();
this.state.empProjects.allocation=this.state.allocation;
this.setState({
empProjects:this.state.empProjects
});
return fetch('http://localhost:3000/Employee/' + this.state.empProjects.id, {
method: 'PUT',
mode: 'CORS',
body: this.state.empProjects,
headers: {
'Content-Type': 'application/json'
}
}).then(res => {
return res;
}).catch(err => err);
}
There are some ways to trigger a render in react:
You send new values down as props to a child component, or
You use a form of state (hooks or setState for example) to update a components state.
In your example, add a setState once the fetch promise has either rejected or resolved, setting the data needed for rendering.
I have restructured the code for better understanding. I believe JSON.stringify() and res.json() may places where you might need to look into.
async submitEmpData(event) {
event.preventDefault();
let { empProjects, allocation } = this.state;
empProjects.allocation = allocation;
// updating the state
this.setState({
empProjects,
});
// calling the api
try {
let res = await fetch("http://localhost:3000/Employee/" + this.state.empProjects.id, {
method: "PUT",
mode: "CORS",
body: JSON.stringify(this.state.empProjects),
headers: {
"Content-Type": "application/json"
}
})
return await res.json();
} catch (err) {
return err;
}
}
Kindly ping me in comments for any clarification
The following method is wrong to change the JSON because the this.state is an object and javascript will check the reference for comparison (See this).
this.state.empProjects.allocation=this.state.allocation;
this.setState({
empProjects:this.state.empProjects
});
instead of this, you can use the spread operator to create a new object:
this.setState({
...this.state, this.state.empProjects: { ...this.state.empProjects, allocation: "NEW value"}
})
Also to send the request using fetch, the body must match with content type:
body: JSON.stringify(this.state.empProjects)

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

Download file using redux flow

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

jQuery ajaxSetup with ES6

How do I replicate the behavior of jQuery's ajaxSetup with vanilla JS (ES6 in this case)?
Here's what I'm trying to achieve. Currently I have in my app.js:
$(document).ready(()=>{
$.ajaxSetup({
data: {'_token': $('meta[name="csrf-token"]').attr('content')}
});
})
So when I perform any ajax request in any other file, _token will be include to the data json object that I'm providing, that way I don't have to specify _token on every call making sure that it's never missed.
How to do this with ES6 only?
Wrap the Fetch api and store your base data and merge that with whatever you send with it.
class MyFetch {
constructor(data) {
this.data = data
}
post(url, data) {
let requestData = {
...this.data,
...data
}
return fetch(url, {
method: 'POST',
body: JSON.stringify(requestData)
})
}
}
let myFetch = new MyFetch({
_token: 'helloworld'
})
myFetch.post('https://httpbin.org/post',{moreData:'more'})
.then((res) => res.json())
.then(json => {
console.log('Data sent:', json.data)
})

Categories

Resources