So i am trying to implement asyncValidation in my redux-form (v7.3.0) input field. The check_email function on the backend returns true if the email already exists and i am using fetch api to call the backend. The api call is successful and returns true or false depending on the email entered but the instead of showing message in form with the input field the there is uncaught error in the console.
The asyncValidate.js file
import { BASE_URL } from "../../config/apiConfig";
const asyncValidate = (values, dispatch, props) => {
let opts = {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'client': localStorage.getItem('client'),
'uid': localStorage.getItem('uid'),
'access-token': localStorage.getItem('access-token')
}
};
return fetch(`${BASE_URL}admin/users/check_email?email=${values.email}`, opts)
.then((res) => {
if(!res.ok){
throw { email: "Something went wrong. Please Type Email again!" }
}
else{
res.json().then((jsonRes) => {
if (jsonRes) {
throw { email: "Email already taken!" };
}
});
}
})
.catch(error => {
throw error
});
};
export default asyncValidate;
As given on the docs the demo validation works and the error message is shown with the input field when the validation fails but the above given validation throws uncaught error in the console.
The problem was with the then method within the else block. The throw statement was inside 2 promises and the redux-form expected it be inside a single promise. So i change it to async/await syntax.
The final code looks like this.
import { BASE_URL } from "../../config/apiConfig";
const asyncValidate = (values, dispatch, props) => {
let opts = {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'client': localStorage.getItem('client'),
'uid': localStorage.getItem('uid'),
'access-token': localStorage.getItem('access-token')
}
};
return fetch(`${BASE_URL}admin/users/check_email?email=${values.email}`, opts)
.then(async (res) => {
if(!res.ok){
throw { email: "Something went wrong. Please Type Email again!" }
}
else{
const jsonRes = await res.json();
if(jsonRes) {
throw { email: "Email already taken!" };
}
}
});
};
export default asyncValidate;
Related
I am working on a crud app using prisma and postgres. Currently I am getting error response when submitting data via POST method. Can someone please tell me what I am doing wrong?
api:
import { NextApiRequest, NextApiResponse } from "next";
import { prisma } from "../../lib/prisma";
const {title, content} = req.body
try {
await prisma.note.create({
data: {
title,
content
}
})
res.status(200).json({message: 'Note Created'})
} catch (error) {
res.status(500).json({error: "Something went wrong"})
Fetch function:
async function create(data: FormData) {
try{
fetch('http://localhost:3000/api/create', {
body: JSON.stringify(data),
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
}).then(() =>{setForm({title: '',content: '',id: '',
})
})
}catch(err){
console.log(err)
}
}
Handle Submit:
const handleSubmit = async (data: FormData) => {
try {
create(data)
} catch (error) {
console.log(error);
}
}
In your create function, you are calling JSON.stringify on an instance of FormData. This will result in an empty object, even if the FormData contains the correct values.
Object.fromEntries(data.entries()) will give you a plain object of the FormData entries, then you can call JSON.stringify on the result of that operation.
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})
})
}
I am working on simple react js application where I am authenticating user and if he/she has successfully logged in I am trying to redirect to home page but I am in some strange situation. Please help me through the below code.
Below is the code for a function fetchAPI to call to server with some input params
function fetchAPI(methodType, url, data, callback){
fetch(url,{
method: methodType,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => callback(data) )
.catch(error => callback(data));
}
Now I am calling it this way
fetchAPI("POST", Constants.LOGIN, data, function(callback) {
if(callback.status == 200) {
console.log(callback.message);
this.props.history.push("/home");
}else if( typeof callback.status != "undefined"){
alertModal("Alert", callback.message);
}
});
The problem with this is that its not redirecting to /home as mention in response condition but only prints success message.
But when I directly use the fetch api like below code it redirects me to /home
can anybody help me out why is this happening with me ??
fetch(Constants.LOGIN, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
if (data.status == 200) {
this.props.history.push("/home");
} else if (typeof data.status != "undefined") {
alertModal("Alert", data.message);
}
})
.catch(error => callback(data));
OK, forget about callbacks, I've been there, no more CALLBACK HELL.
Use promises always, and you can simplify everything by using async/await:
async function fetchAPI(methodType, url, data){
try {
let result = await fetch(url, {
method: methodType,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
}); // wait until request is done
let responseOK = response && response.ok;
if (responseOK) {
let data = await response.json();
// do something with data
return data;
} else {
return response;
}
} catch (error) {
// log your error, you can also return it to handle it in your calling function
}
}
in your React Component:
async someFunction(){
let result = await fetchAPI("POST", Constants.LOGIN, data); // wait for the fetch to complete
if (!result.error){
// get whatever you need from 'result'
this.props.history.push("/home");
} else {
// show error from 'result.error'
}
}
Now your code looks more readable!
The errors in fetch are in either result.error or result.statusText, I stopped using fetch a long time ago, switched to Axios. Have a look at my answer on some differences between the 2 Here.
EDIT BASED ON YOUR RESPONSE
Ok, based on the code you posted:
import React from "react";
import Constants from "../Constants.jsx";
import { withRouter } from "react-router-dom";
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: "",
errors: []
};
}
showValidationErr(elm, msg) {
this.setState(prevState => ({
errors: [...prevState.errors, { elm, msg }]
}));
}
clearValidationErr(elm) {
this.setState(prevState => {
let newArr = [];
for (let err of prevState.errors) {
if (elm != err.elm) {
newArr.push(err);
}
}
return { errors: newArr };
});
}
onEmailChange(e) {
this.setState({ email: e.target.value });
this.clearValidationErr("email");
}
onPasswordChange(e) {
this.setState({ password: e.target.value });
this.clearValidationErr("password");
}
submitLogin(e) {
e.preventDefault();
const { email, password } = this.state;
if (email == "") {
this.showValidationErr("email", "Email field cannot be empty");
}
if (password == "") {
this.showValidationErr("password", "Password field cannot be empty");
}
if (email != "" && password != "") {
var data = {
username: this.state.email,
password: this.state.password
};
// I added function keyword between the below line
async function someFunction(){
let result = await fetchAPI("POST", Constants.LOGIN, data); // wait for the fetch to complete
if (!result.error){
this.props.history.push("/home"); // Here is the error
} else {
// show error from 'result.error'
}
}
someFunction();
}
}
render() { ......................
####-----This is function definition------####
async function fetchAPI(methodType, url, data){
try {
let response = await fetch(url, {
method: methodType,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
}); // wait until request is done
let responseOK = response && response.ok;
if (responseOK) {
let data = await response.json();
// do something with data
return data;
} else {
return response;
}
} catch (error) {
return error;
// log your error, you can also return it to handle it in your calling function
}
}
This is the idea, you should make async the function that is calling the API. In your example, your function submitLogin has to be async since it will call an async function inside. As long as you call an async function, the caller MUST be async, or handle the promise accordingly. This is how it should be:
async submitLogin(e) {
e.preventDefault();
const { email, password } = this.state;
if (email == "") {
this.showValidationErr("email", "Email field cannot be empty");
}
if (password == "") {
this.showValidationErr("password", "Password field cannot be empty");
}
if (email != "" && password != "") {
var data = {
username: this.state.email,
password: this.state.password
};
let result = await fetchAPI("POST", Constants.LOGIN, data); // wait for the fetch to complete
if (!result.error) {
this.props.history.push("/home"); // Here is the error
} else {
// show error from 'result.error'
}
}
If the function is correctly bound in the constructor, you won't have any problems with this. It seems that you are not binding the submitLogin function in the constructor, which will give you problems with the context of this. This is how it should be bound:
constructor(props) {
super(props);
this.state = {
email: "",
password: "",
errors: []
};
// bind all functions used in render
this.submitLogin = this.submitLogin.bind(this);
}
Have a look at this article to learn more about the problem with the context of this.
Now, based on the code you provided, seems to me that you are in uncharted territory. If you think that you are finding the routing hard or the async/await is not clear, I suggest you don't use them, and first master the React basics (the syntax problem you are having is an example, you shouldn't have put that function there, also the binding issue with this).
Have a read at this post for example, to have a general idea and I also suggest you try other more simple examples before using async, fetch, or routing. When you get the React lifecycle clear, you can continue from there, and use async functions, and then routers.
I also suggest you follow the examples in the Official docs and also have a look at this post to have a better understanding of async/await.
These suggestions are of course given so that you get to master React with clear fundamentals, and in the future don't have any problems with the basics! :)
So I am trying to create a user using redux-form. I have an express post route on the backend. NOTE: using redux-thunk for middleware, whatwg-fetch with webpack and babel-polyfill.
routes.post('/signup', async (req, res) => {
try {
const createdUser = await userController.createUser(req.body);
const JSONCreatedUser = JSON.stringify(createdUser);
res.json({
confirmation: 'success',
result: createdUser,
});
return JSONCreatedUser;
} catch (error) {
res.statusMessage = error.toString();
res.status(409).json({
confirmation: 'failure',
error: error.toString(),
});
}
});
So the problem I am having is that when I use postman. I will get the entire user object back.
But when I submit it using form I only get
Apimanager.js
export const signUserUpApi = async (url, params) => {
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
});
const { status, statusText } = response;
if (status === 409) {
throw new Error(statusText);
}
return response;
} catch (error) {
throw new Error(error.toString());
}
};
action.js
import constants from '../constants';
import { signUserUpApi } from '../utils/APIManager';
const signUserUpUrl = process.env.SIGN_USER_UP_URL || 'http://localhost:3000/user/signup';
export const signUserUp = (user) => {
return async (dispatch) => {
try {
const createdUser = await signUserUpApi(signUserUpUrl, user);
dispatch({
type: constants.SIGN_USER_UP,
user: createdUser,
});
return createdUser;
} catch (error) {
throw new Error(error);
}
};
};
export const signUserIn = (user) => {
return {
type: constants.SIGN_USER_UP,
user,
};
};
What I am trying to do is to get the User Object I created when I submit the form and redirect back to the page.
This is what I get back and it did create the user.
First thing, I need is why am I getting the https status code back and not the user object?
Second thing, what are the ways to redirect to the home page when a user successfully signed up logged in.
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.