Update state values from a different file in react native - reactjs

I am keeping all my functions in one file, and calling those functions in activities where needed in my react native project. Now in one of my functions which has a fetch api, I am fetching data from my online server and printing the response after a successful query.
Now I want to be able to update state value with the response from the fetch method in the then.
App.js
...
import {registerUsers} from './src/utils/api.js'
export class App extends Component{
state = {
isLoggedIn:false,
isLoading:false,
isAppready:false
}
_Register = (email,password,fullName) =>{
this.setState({isLoading:true})
//calling the register user function here
registerUsers(email,password,fullName)
}
...
The api file
import React from 'react'
import { Alert } from 'react-native';
export function registerUsers(email, password, fullName) {
fetch('http://00.00.00.00/reg/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
userEmail: email,
userPassword: password,
userFullName: fullName
})
}).then((response) => response.json())
.then((responseJson) => {
//setState({ isLoggedIn: true, isLoading: false })
// Showing response message coming from server after inserting records.
Alert.alert(responseJson);
}).catch((error) => {
// this.setState({ isLoggedIn: true, isLoading: false })
console.error(error);
});
}
I would now want to update the state values thus isLoggedIn: true and isLoading:false after the fetch method has been processed. The problem now is that I can't figure it out where to update the state values since I am calling the registerUsers function from a different file.
I would be grateful if someone could share an idea as to how to figure this out. Thanks

registerUsers should return the promise. That way, you can handle the response directly inside your component:
API:
export function registerUsers(email, password, fullName) {
return fetch('http://00.00.00.00/reg/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
userEmail: email,
userPassword: password,
userFullName: fullName
})
}).then( response => response.json());
}
Component:
import {registerUsers} from './src/utils/api.js'
export class App extends Component{
state = {
isLoggedIn:false,
isLoading:false,
isAppready:false
}
_Register = (email,password,fullName) =>{
this.setState({isLoading:true})
//calling the register user function here
registerUsers(email, password, fullName)
.then( responseJson => {
this.setState({
isLoggedIn: true,
isLoading: false,
data: responseJson
});
}).catch( error => {
this.setState({ isLoggedIn: false, isLoading: false });
});
}

Related

Redux Actions must be plain objects error

I am developing a frontend application using ReactJS. I haven't used redux before and I am getting an error.
I have the following code:
import { connect } from 'react-redux';
import PharmacistPreregisterComponent from "../components/PharmacistPreregisterComponent";
import { postPreregisteredPharmacist } from "../actions";
const mapDispatchToProps = dispatch => ({
onClick: (email, drugstoreId, alert) => {
dispatch(
postPreregisteredPharmacist(email, drugstoreId, alert)
);
}
});
export default connect (
null,
mapDispatchToProps
)(PharmacistPreregisterComponent)
In PharmacistPreregisterComponent the method:
handleSubmit(event) {
event.preventDefault();
this.onClick(
this.state.email,
this.state.drugstoreId,
this.state.alertMessage);
this.setState({
email: '',
drugstoreId: '',
alertMessage: ''
});
}
And the following action:
const PREREGISTER_PHARMACIST_SAVE_URL = "http://localhost:3000/admin/preregister/add"
export function postPreregisteredPharmacist(email, drugstoreId, alert) {
return dispatch => {
console.log("in action");
return fetch(PREREGISTER_PHARMACIST_SAVE_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ "email": email, "drugstoreId": drugstoreId})
}).then ( response => {
console.log(response);
}).catch( error => {
console.log(error);
})
}
}
When submitting the form I get Actions must be plain objects. Use custom middleware for async actions. and I can't seem to figure out what the problem is.
As suggested by you in the comments, since you do not wish to update redux state based on the API request you can simply convert you function into a normal function instead of a action
Also consider setting the state to empty only if the API request is successful
import PharmacistPreregisterComponent from "../components/PharmacistPreregisterComponent";
import { postPreregisteredPharmacist } from "../actions";
handleSubmit(event) {
event.preventDefault();
postPreregisteredPharmacist (
this.state.email,
this.state.drugstoreId,
this.state.alertMessage
).then((response) => {
console.log(response);
this.setState({
email: '',
drugstoreId: '',
alertMessage: ''
});
});
}
export default PharmacistPreregisterComponent)
const PREREGISTER_PHARMACIST_SAVE_URL = "http://localhost:3000/admin/preregister/add"
export function postPreregisteredPharmacist(email, drugstoreId, alert) {
return fetch(PREREGISTER_PHARMACIST_SAVE_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ "email": email, "drugstoreId": drugstoreId})
})
}

How to get the headers of a reponse in a fetch request?

I'm trying to get the headers of a response following a fetch request and to assign some values to my redux state. I can only get access to the promise of the headers though. I would appreciate some help on figuring out why.
export function sign_in(email, password){
return (dispatch) => {
dispatch({ type: 'LOGGING_USER_IN' });
return fetch("http://localhost:3000/api/v1/auth/sign_in" ,{
method: "POST",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json; charset=utf-8"
},
body: JSON.stringify({
email: email,
password: password
})
})
.then(response => {
dispatch({type:'LOGGING_USER_IN_SUCCESS', payload: response.headers})
})
.catch(error =>{
dispatch({type:'LOGGING_USER_IN_FAILURE', payload: error, error:true})
})
}
};
My reducer:
export default function authReducer(state = {
isLoaded: false,
}, action) {
switch (action.type) {
case 'LOGGING_USER_IN':
return {
...state,
}
case 'LOGGING_USER_IN_SUCCESS':
// console.log(action.payload.get("access-token"))
return {
// ...state,
isLoaded: true,
user: action.payload}
case 'LOGGING_USER_IN_FAILURE':
return{
...state,
isLoaded: true,
errorMessage: action.payload.message}
default:
return state;
}
}
response.headers is a Headers{} object that represents the HTTP response headers.
You need to lookup the headers that you want to dispatch by calling get(name), or you can get all the headers by using forEach like this:
.then(response => {
const payload = {};
response.headers.forEach((value, name) => payload[name] = value);
dispatch({type:'LOGGING_USER_IN_SUCCESS', payload })
})
demo
A side note:
Only the following headers are exposed:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
So if you want to access any other headers, you will need to set the Access-Control-Expose-Headers header appropriately.
source

Unhandled Rejection (SyntaxError): Unexpected end of JSON input

I have a login form (Username and Password) written in a React JS environment; the form consumes a REST API that contains the user credentials. I'm using the Fetch method to consume the API, but it errors out. I need to access the service via POST, but when I check (via chrome console - Network tab ) how my application is accessing the service, it states that the request method used is GET. How do I modify my code to access the form using post? Here is my code snippet I'm using to consume the web APT:
class Login extends Component {
//constructor
constructor() {
super();
this.state={
data: [],
}
}
//componet did mount method
componentDidMount(){
return fetch('http://myjson.com/file')
.then((response)=>response.json())
.then((responseJson)=>
{
this.setState({
data:responseJson.token
})
console.log(this.state.data)
})
}
I researched using the request.method but I'm uncertain how to implement it into the code. Could I get some help with this please? ...thanks in advance
fetch('http://myjson.com/users/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: 'userName',
password: 'pwd',
})
})
Here is fetch docs
Edit
componentDidMount(){
return fetch('http://myjson.com/users/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: 'userName',
password: 'pwd',
})
})
.then((response)=>response.json())
.then((responseJson)=>
{
this.setState({
data:responseJson.token
})
console.log(this.state.data)
})
}

Lost in testing Redux vs Sinon/React

Im completely lost on how to test the React components itself which include XHR calls. I have below items
LoginForm
Redux with action + reducer
Sinon (for spy/xhr stuff)
Chai
Below is some basic setup code. Please note that its not the full code but i guess you get the idea:
Form
class Form extends React.Component {
constructor() {
super();
this.state = {
username: null,
password: null
};
this.handleForm = this.handleForm.bind(this);
}
handleForm(e) {
e.preventDefault();
this.props.dispatch(authenticateUser(this.state.username, this.state.password));
}
render() {
<Form>
}
}
Action
export function authenticateUser(username, password) {
return function(dispatch, getState) {
dispatch({type: 'AUTHENTICATION_USER'});
fetch(getState().config.login_endpoint, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: {
username: username,
password: password
}
}).then(function (data) {
if(data.status === 404) {
dispatch({type: 'AUTHENTICATION_USER_NOTFOUND', payload: data.statusText});
} else {
dispatch({type: 'AUTHENTICATION_USER_FULFILLED', payload: data.json()});
}
}).catch(function (error) {
dispatch({type: 'AUTHENTICATION_USER_REJECTED', payload: error.message});
});
};
}
Reducer
export default function (state = {
loading: false,
errorMessage: null,
passwordSent: false
}, action) {
switch (action.type) {
case 'AUTHENTICATION_USER':
return {...state, loading: true, errorMessage:null};
case 'AUTHENTICATION_USER_NOTFOUND':
case 'AUTHENTICATION_USER_REJECTED':
return {...state, loading: false, errorMessage: action.payload};
case 'AUTHENTICATION_USER_FULFILLED':
window.location = '/';
break;
}
return state;
}
To test all this i setup a few test cases:
describe('components/LoginForm', () => {
it('should push username and password in xhr call after form submit');
it('redirects in case of succesfull login to the configured endpoint');
it('should show an user error on a 404 response');
it('should show an user error on a 500 response');
});
Testing of all the internal component stuff is already finished but no idea how we can handle the XHR stuff and also the redux events. I checked this page as reference but i really dont get the idea and it is also focussed on Jest instead
http://redux.js.org/docs/recipes/WritingTests.html
Hope that someone could bump me into the correct direction on how to handle this.
Thanks

How to make a rest post call from ReactJS code?

I am new to ReactJS and UI and I wanted to know how to make a simple REST based POST call from ReactJS code.
If there is any example present it would be really helpful.
Straight from the React Native docs:
fetch('https://mywebsite.example/endpoint/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
})
})
(This is posting JSON, but you could also do, for example, multipart-form.)
Also see docs for ReactJS AJAX FAQs if not using React Native.
React doesn't really have an opinion about how you make REST calls. Basically you can choose whatever kind of AJAX library you like for this task.
The easiest way with plain old JavaScript is probably something like this:
var request = new XMLHttpRequest();
request.open('POST', '/my/url', true);
request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
request.send(data);
In modern browsers you can also use fetch.
If you have more components that make REST calls it might make sense to put this kind of logic in a class that can be used across the components. E.g. RESTClient.post(…)
Another recently popular packages is : axios
Install : npm install axios --save
Simple Promise based requests
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
you can install superagent
npm install superagent --save
then for make post call to server
import request from "../../node_modules/superagent/superagent";
request
.post('http://localhost/userLogin')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send({ username: "username", password: "password" })
.end(function(err, res){
console.log(res.text);
});
As of 2018 and beyond, you have a more modern option which is to incorporate async/await in your ReactJS application. A promise-based HTTP client library such as axios can be used. The sample code is given below:
import axios from 'axios';
...
class Login extends Component {
constructor(props, context) {
super(props, context);
this.onLogin = this.onLogin.bind(this);
...
}
async onLogin() {
const { email, password } = this.state;
try {
const response = await axios.post('/login', { email, password });
console.log(response);
} catch (err) {
...
}
}
...
}
I think this way also a normal way. But sorry, I can't describe in English ((
submitHandler = e => {
e.preventDefault()
console.log(this.state)
fetch('http://localhost:5000/questions',{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(this.state)
}).then(response => {
console.log(response)
})
.catch(error =>{
console.log(error)
})
}
https://googlechrome.github.io/samples/fetch-api/fetch-post.html
fetch('url/questions',{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(this.state)
}).then(response => {
console.log(response)
})
.catch(error =>{
console.log(error)
})
Here is a the list of ajax libraries comparison based on the features and support.
I prefer to use fetch for only client side development or isomorphic-fetch for using in both client side and server side development.
For more information on isomorphic-fetch vs fetch
Here is a util function modified (another post on stack) for get and post both. Make Util.js file.
let cachedData = null;
let cachedPostData = null;
const postServiceData = (url, params) => {
console.log('cache status' + cachedPostData );
if (cachedPostData === null) {
console.log('post-data: requesting data');
return fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(params)
})
.then(response => {
cachedPostData = response.json();
return cachedPostData;
});
} else {
console.log('post-data: returning cachedPostData data');
return Promise.resolve(cachedPostData);
}
}
const getServiceData = (url) => {
console.log('cache status' + cachedData );
if (cachedData === null) {
console.log('get-data: requesting data');
return fetch(url, {})
.then(response => {
cachedData = response.json();
return cachedData;
});
} else {
console.log('get-data: returning cached data');
return Promise.resolve(cachedData);
}
};
export { getServiceData, postServiceData };
Usage like below in another component
import { getServiceData, postServiceData } from './../Utils/Util';
constructor(props) {
super(props)
this.state = {
datastore : []
}
}
componentDidMount = () => {
let posturl = 'yoururl';
let getdataString = { name: "xys", date:"today"};
postServiceData(posturl, getdataString)
.then(items => {
this.setState({ datastore: items })
console.log(items);
});
}
Here is the simple method to define and call post APIs in reactjs. Install axios using command npm install axios and call post req method wherever you want, it will return array that contains 100 elements.
// Define post_req() Method in authAction.js
import axios from 'axios';
const post_req = (data) => {
return new Promise((resolve, reject) => {
const url = 'https://jsonplaceholder.typicode.com/posts'
const header = {
"Access-Control-Allow-Origin": "*",
"Content-Type: application/json"
}
axios({
method: 'post',
url: url,
data: data,
headers: header
});
.then((res)=>{resolve(res);})
.catch((err)=>{reject(err);})
})
}
// Calling post_req() Method in react component
import React, { Component } from 'react';
import { post_req } from 'path of file authAction.js'
class MyReactComponent extends Component {
constructor(props) {
super(props);
this.state = {
myList:[]
};
}
componentDidMount() {
let data = {
.......
}
this.props.post_req(data)
.then((resp)=>{this.setState({myList:resp.data})})
.catch((err)=>{console.log('here is my err',err)})
}
render() {
return (
<div>
....
</div)
}
}
export default MyReactComponent;
import React ,{useState}from 'react';
import Axios from 'axios';
export default function Formlp()
{
const url ="";
const [state, setstate] = useState({
name:"",
iduser:""
})
function handel(e){
const newdata={...state}
newdata[e.target.id]=e.target.value
setstate(newdata);
}
function submit(e)
{
e.preventDefault();
// Axios.post(url,{name:state.name,iduser:state.iduser}).then( res=>{console.log(res)});
console.log(state)
}
return (
<div onSubmit={ (e)=> submit(e)}>
<input onChange={ (e)=>handel(e) } id="name" value={state.name} placeholder="name" type="text" >
<input onChange={ (e)=>handel(e) } id="iduser" value={state.iduser} placeholder="iduser" type="text" >
<button>submit</button>
</form>
</div>
);
}
Here is a quick example for v18+ while handling form data and creating a POST request with the data.
async function handleOrderSubmit(event){
event.preventDefault()
try{
const formData= {name: event.target.name.value, email: event.target.email.value, message: event.target.name.message}
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
};
const response = await fetch('https://www.example.com/form', requestOptions);
const data = await response.json();
navigate("/form-response", { state: {data: data, status: true} })
}
catch(error){
navigate("/form-response", { state: {status: false} })
}
}
Note 1: Using status on '/form-response' page, you can customise what to show user. For true, you can show a different section and for false a different one.
Note 2: If the status is successful, you can access data on the next page also and customise it according to user information.
Note 3: event.preventDefault() is important to avoid page reloading.
Here is an example: https://jsfiddle.net/69z2wepo/9888/
$.ajax({
type: 'POST',
url: '/some/url',
data: data
})
.done(function(result) {
this.clearForm();
this.setState({result:result});
}.bind(this)
.fail(function(jqXhr) {
console.log('failed to register');
});
It used jquery.ajax method but you can easily replace it with AJAX based libs like axios, superagent or fetch.

Resources