I am unable to get API data in redux store - api

I am trying to build an app to add and delete items. I am using an API(Link of API documentation below). I can post and get data from API to the store. But I am unable to show the saved items on UI. And the getBooks function seems to be not working. Can anyone please help me?
Link to API documentation: https://www.notion.so/Bookstore-API-51ea269061f849118c65c0a53e88a739
Here is the code, I have used.
export const addBook = (book) => async (dispatch) => {
await fetch(url, {
method: 'POST',
body: JSON.stringify(book),
headers:{
'Content-type': 'application/json; charset=UTF-8',
}
})
.then(() => dispatch({type: ADD_BOOK, book}))
}
export const removeBook = (index) => async (dispatch) => {
await fetch(`${url}/${index}`, {
method: 'DELETE',
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
})
.then(() => dispatch({ type: REMOVE_BOOK, index }));
};
export const getBooks = () => async (dispatch) => {
await fetch(url)
.then((res) => res.json())
.then((book) => {
const booksArray = [];
Object.keys(book).forEach((key) => {
booksArray.push({
item_id: key,
author: book[key][0].author,
title: book[key][0].title,
category: book[key][0].category,
});
});
dispatch({ type: GET_BOOKS, booksArray});
});
};

Related

seting auth token in react native not working

i am trying to set auth token in react native but it is not working.the api call to the url is woeking and data is saved to db but the token doesnot work
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/register',
data: Data,
})
.then(function (response) {
console.log('working');
ReactSession.setStoreType('Bearer', response.data.token);
ReactSession.set('username', 'Meon');
})
.catch(error => {
alert(JSON.stringify(error.response.data));
});
}
i get this error
console.log(response); returns the following
I use AsyncStorage together with fetch to set mine and then when i want to use it , I also call AsyncStorage from '#react-native-async-storage/async-storage';
After setting the state like this,
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
I try to simulate a Login
To login looks like this :
FunctionLogin = async () => {
let item = {email, password};
fetch('http://192.168.1.101/api/auth/sign-in', {
method: 'POST',
mode: 'cors',
headers: {
'Accept': 'application/json',
'Content-type': 'application/json',
},
body: JSON.stringify(item),
})
.then(response => response.json())
.then(async (responseJson) => {
if (responseJson.message === 'OK') {
var token = responseJson.token;
await AsyncStorage.setItem('email', email);
await AsyncStorage.setItem('token', token);
navigation.replace('Dashboard');
} else {
alert(responseJson);
}
})
.catch(error => {
console.error(error);
});
}
To use it in any page, I use it like this , later i reference the function in useEffect
showdata = async () => {
let token = await AsyncStorage.getItem('token');
alert(token);
};
Suppose I want to get transaction list from my endpoint to display data I do it like this
getTransactionsList = async () => {
let token = await AsyncStorage.getItem('token');
let email = await AsyncStorage.getItem('email');
var url = 'https://192.168.1.101/api/user-data/get-transactionby-email/';
fetch(url + email, {
method: 'GET',
headers: {
'Content-type': 'application/json',
'Authorization': `Bearer ${token}`,
},
})
.then(response => response.json())
.then(responseJson => {
setTransaction_details(responseJson);
setLoading(false);
});
};
Then suppose i want to call it inside useEffect, I do like this
useEffect(() => {
getTransactionsList();
});
Thats what and how i do it and it works fine. If you also know how to use Redux, its still a good one as well.

How do I use Async Storage to save Data Locally after calling fetch in react native?

I want to use Async storage. Each time I call without the async function like this
FunctionLogin = () =>{ //other methods here ........ }
and this does not have await anywhere, it saves to the database but when i use let email = AsyncStorage.getItem('email'); to call it back, it does not return anything like the email just [Object object] is what i see
how do I resolve this
the fetch method to save to async storage looks like this
`FunctionLogin = async () =>{
//navigation.replace('VirtualAccountPage');
let item = {email, password,phone};
fetch('https://xxxxxxxxxxxxxxxx/api/sign-up', {
method: 'POST',
mode: 'cors',
headers: {
Accept: 'application/json',
'Content-type': 'application/json',
},
body: JSON.stringify(item),
})
.then(response => response.json())
.then(responseJson =>{
if (responseJson.message === 'User created Successfully') {
await AsyncStorage.setItem('email', email);
await AsyncStorage.setItem('phone', phone);
alert('I am Registered');
navigation.replace('VirtualAccountPage');
} else {
alert(responseJson);
}
})
.catch(error => {
console.error(error);
});
}`
the function to call it back, so it can be used as persistence looks thus
` FunctionUserDetails = () => {
let email = AsyncStorage.getItem('email');
let phone = AsyncStorage.getItem('telephone');
//navigation.replace('Dashboard');
alert(email);
};`
How do i get this to work?
I want to be able to save data locally using async storage so i can be able to persist the data on some other screens etc. I tried several things to see if It could work as expected, i do not get to see it work as i want.
to get the value from AsyncStorage you need to use await and the function should start with async
fetch('https://xxxxxxxxxxxxxxxx/api/sign-up', {
method: 'POST',
mode: 'cors',
headers: {
Accept: 'application/json',
'Content-type': 'application/json',
},
body: JSON.stringify(item),
})
.then(response => response.json())
.then(async (responseJson) =>{ // add async here
if (responseJson.message === 'User created Successfully') {
await AsyncStorage.setItem('email', email);
await AsyncStorage.setItem('phone', phone);
alert('I am Registered');
navigation.replace('VirtualAccountPage');
} else {
alert(responseJson);
}
})
.catch(error => {
console.error(error);
});
const FunctionUserDetails = async () => { // change this
let email = await AsyncStorage.getItem('email'); // change this
let phone = await AsyncStorage.getItem('telephone'); // change this
//navigation.replace('Dashboard');
alert(email);
};`
Install this updated async-storage npm
Try implementing using below code:
fetch('https://xxxx/login', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-type': 'application/json',
},
body: JSON.stringify(item),
})
.then(response => response.json())
.then(async (responseJson) =>{ // add async here
if (responseJson.stausCode === 200) {
await AsyncStorage.setItem('name', name);
} else {
alert(responseJson);
}
})
.catch(error => {
console.error(error);
});

How to upload a file from asset-library to Express server in React Native?

I have my video file assets-library://asset/asset.mov?id=766BDDA3-F0EB-43B3-B719-4EA851692B91&ext=mov and I am trying to now upload it to my Express server.
const uri = 'http://localhost:3000/upload';
const formData = new FormData();
formData.append('file', 'assets-library://asset/asset.mov?id=766BDDA3-F0EB-43B3-B719-4EA851692B91&ext=mov');
fetch(uri, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data boundary=gc0p4Jq0M2Yt08jU534c0p'
},
body: formData
})
.then(res => {
console.log({ res });
})
.catch(err => {
console.log(err);
});
My Express Server API endpoint:
app.post('/upload', upload.single('file'), (req, res) => {
console.log(req.file);
res.send('Done');
});
The console.log(req.file) returns undefined.
Do I need to do an extra step in between?
As per Gavin's comment, I tried out RNFetchBlob.
RNFetchBlob.fetch(
'POST',
'http://localhost:3000/upload',
{
'Content-Type': 'multipart/form-data'
},
[
{
name: 'file',
filename: 'vid.mov',
data: RNFetchBlob.wrap(file)
}
]
)
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
});
My application crashes without any logs on Xcode or in the Debugger.

Only navigate to next page when asynchronos actions are complete? React-native

So, I have a bit of a tricky situation here for me as a beginner with redux as well as react-native.
When the user loggs in, I want to update the Redux state with the user data. I call a login methond where I get a web token. Directly afterwards I want to dispatch two asynchronous actions with redux-thunk. The problem is:
By the time these actions are dispatched and I have the response from the API, I've already navigated to another screen and the data to render the list is not in the Redux state.
The Question: How can I "hold" the program until my state is updated and then navigate to the next page?
This is what happens when the user logs in:
fetch("http://10.0.2.2:8000/api/api-token-auth/", {
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: this.props.email,
password: this.props.password,
})
}).then((response) => response.json()
).then((jResponse) => {
console.log(jResponse);
this._onValueChange('token_id', jResponse.token);
this.props.loginUserSuccess();
this.props.navigation.navigate('MainMenue');
}).catch((error) => {
console.log(error);
this.props.loginUserFail();
})
}
Somewhere during the login these two actions sould be dispatched completly and the state should be updated:
export const profileLoad = () => {
return (dispatch) => {
AsyncStorage.getItem('token_id')
.then((token_id) => fetch("http://10.0.2.2:8000/api/profile/", {
method: "GET",
headers: {
'Authorization': 'JWT ' + token_id
}
})
.then((response) => response.json())
.then((answer) => {
dispatch({ type: PROFILE_LOAD, payload: answer});
})
.done());
}
}
export const productsLoad = () => {
return (dispatch) => {
AsyncStorage.getItem('token_id')
.then((token_id) => {
fetch("http://10.0.2.2:8000/api/profile/products/", {
method: "GET",
headers: {
'Authorization': 'JWT ' + token_id
}
}).then((anser) => anser.json())
.then((response)=> {
dispatch ({ type: PRODUCTS_LOAD, payload: response})
})
}
).done();
}
}
Then I want to navigate the another screen andrender a list (with ListView) to display the JSON data from products and profiles.
-- > So I finally figured it out.
Solution
1.) Return promises from action creators as stated
2.) Make sure you put a callback function in the then method
export const loadAllProfileData = ({navigate}) => {
return (dispatch) => {
dispatch(profileLoad())
.then(() => dispatch(productsLoad()))
.then(() => navigate('MainMenue'))
};
}
export const profileLoad = () => {
return (dispatch) => {
return AsyncStorage.getItem('token_id')
.then((token_id) => fetch("http://10.0.2.2:8000/api/profile/", {
method: "GET",
headers: {
'Authorization': 'JWT ' + token_id
}
})
).then((response) => response.json())
.then((answer) => {
dispatch({ type: PROFILE_LOAD, payload: answer});
})
}
}
export const productsLoad = () => {
return (dispatch) => {
return AsyncStorage.getItem('token_id')
.then((token_id) =>
fetch("http://10.0.2.2:8000/api/profile/products/", {
method: "GET",
headers: {
'Authorization': 'JWT ' + token_id
}
})
).then((answer) => answer.json())
.then((response)=> {
dispatch ({ type: PRODUCTS_LOAD, payload: response})
})
}
}
You can return promises from your action creators and chain them with then. You can do that by simply adding return AsyncStorage.getItem() ... to your action creators. Then you can do:
fetch(url) //login
.then(dispatch(profileLoad))
.then(dispatch(productsLoad))
.then(this.props.navigation.navigate('MainMenue'))
.catch(err => //handle error)
Read more about promises chaining.
Edit: A simple example would be:
import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk'
import fetch from 'node-fetch';
const ROOT_URL = 'https://jsonplaceholder.typicode.com';
const FETCH_DATA = 'FETCH_DATA';
const url = `${ROOT_URL}/users`;
function fetchData() {
return (dispatch) => {
return fetch(url)
.then(res => res.json())
.then(data => {
dispatch({
type: FETCH_DATA,
payload: data[0].name
});
})
}
}
function reducer(state = [], action) {
if (action.type === FETCH_DATA) {
console.log('Action.payload:', action.payload);
}
switch (action.type) {
case 'FETCH_DATA':
return [...state, action.payload];
default:
return state;
};
}
let store = createStore(
reducer,
applyMiddleware(thunkMiddleware)
)
store.subscribe(() =>
console.log('Store State: ', store.getState())
)
fetch(url)
.then(res => res.json())
.then(data => data)
.then(store.dispatch(fetchData()))
.then(store.dispatch(fetchData()))

fetch response.json() gives responseData = undefined

When using fetch:
fetch(REQUEST_URL, {
method: 'get',
dataType: 'json',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then((response) =>
{
response.json() // << This is the problem
})
.then((responseData) => { // responseData = undefined
console.log(responseData);
});
}).catch(function(err) {
console.log(err);
})
.done();
The following works works, do you know why? :
JSON.parse(response._bodyText)
The chaining response should look more like this, specifically the response.json part. Then you should get an Object back in console.log.
.then(response => response.json())
.then(response => {
console.log(response)
}
Fetch is a little hard to get your head around. I am new to this so dont shoot me down if flames here but response data is another promise and you need to return response data and then handle that promise with yet another then statement where you can finally log the response, also your are missing some return statements in your promises:
var makeRequest = function(){
fetch('https://jsonplaceholder.typicode.com/posts/1', {
method: 'get',
dataType: 'jsonp',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then((response) => {
return response.json() // << This is the problem
})
.then((responseData) => { // responseData = undefined
addTestToPage(responseData.title);
return responseData;
})
.catch(function(err) {
console.log(err);
})
}
function addTestToPage(textToAdd){
var para = document.createElement("p");
var node = document.createTextNode(textToAdd);
para.appendChild(node);
var element = document.getElementsByTagName("body")[0];
element.appendChild(para);
}
makeRequest();
hope that helps see: https://jsfiddle.net/byz17L4L/
Here's how it finally worked out in my case:
fetch('http://localhost:3001/questions', {
method: 'GET',
headers: {
"Accept": "application/json",
'Content-Type': 'application/json'
}
})
.then(response => { return response.json();})
.then(responseData => {console.log(responseData); return responseData;})
.then(data => {this.setState({"questions" : data});})
.catch(err => {
console.log("fetch error" + err);
});
}
because you didn't return response.json() in the first then.
import React, {useEffect} from 'react';
useEffect(() => {
getRecipes();
}, []);
const getRecipes = async () => {
const response = await fetch(
`https://........`
);
const data = await response.json();
console.log(data);
Use this method You can easily fatch data.
fetch(weatherIng + zipCode +apiKey)
.then(response => response.json())
.then(response => {
console.log(response.main);
this.setState({
weather: ((response.main.temp * (9/5))-459.67).toFixed(0),
humidity:((response.main.humidity * (9/5))-459.67).toFixed(0)
})
It will think that you are trying to declare something if you don't enclose it in its own:
.then(response => {
console.log(response.main);
}) . " around the this.setState