history.push not working in fetch callback - reactjs

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! :)

Related

Generic function to request api with Axios

I am trying to build a generic function for my endpoints, using Axios and React. Generic because I have always the same header and I do not want to repeat a lot of code for each of my components.
To do that, I built this function (sorry, a lot of comments that I will remove after of course) :
export const getRequest = ( endpoint ) => axios
.get( env._URL_SERVER_ + endpoint, { headers: getHeaders() } )
.then((res) => {
// Success
console.log(res);
return {error: false, response: res.data};
})
.catch((error) => {
// Error
if (error.response) {
/*
* The request was made and the server responded with a
* status code that falls out of the range of 2xx
*/
console.log(error.response.data);
console.log(error.response.status);
return {error: true, status: error.response.status, data: error.response.data};
} else if (error.request) {
/*
* The request was made but no response was received, `error.request`
* is an instance of XMLHttpRequest in the browser and an instance
* of http.ClientRequest in Node.js
*/
console.log(error.request);
return {error: true, data: error.request };
} else {
// Something happened in setting up the request and triggered an Error
console.log('Error', error.message);
return {error: true, data: error.message}
}
});
Ant then in my components I do that :
getSchools = () => {
this.setState({
loadingSchools: true
}, () => {
getRequest(`/schools?name=${this.state.filterByName}&city=${this.state.filterByCity}&school_type_id=${this.state.filterBySchoolTypeId}&page=${this.state.selectedPage}`)
.then((response) => {
// there is an error
if (!response.error) {
this.setState({
schools: response.response.data,
meta: response.response.meta,
links: response.response.links
})
} else {
this.setState({
error: true,
errorMessage: response.data,
})
}
})
.then(() => {
this.setState({loadingSchools : false});
})
})
}
It works fine. I tested it in several situation (all is OK - 200, not found - 404, no response). But is it a good practice ? I feel that there is a lot of codes in the parent component. Maybe I complicate my life?
Here is how I've done it:
var URL_BACKEND = "http://localhost:5000/";
// Create Function to handle requests from the backend
callToBackend = async (ENDPOINT, METHOD) => {
const options = {
url: `${URL_BACKEND}${ENDPOINT}`,
method: METHOD,
headers: {
Accept: "application/json",
"Content-Type": "application/json;charset=UTF-8",
},
};
const response = await axios(options);
return response.data;
}
// Then you make a call with the exact endpoint and method:
const response = await this.callToBackend('createSetupIntent', 'POST');
console.log(JSON.stringify(response));
create one common file for base URL let's say api.js
// api.js file code
export const apiUrl = axios.create({
baseURL: 'http://localhost:5000',
});
Register file
// register.js file code
import { apiUrl } from './api';
try {
const resp = await apiUrl.post('/api/register', {
username,
email,
password,
});
const { data, status } = resp;
if (Object.keys(data).length && status === 200) {
// received api data successfully
console.log('API response', data);
}
} catch (err) {
console.log(err);
}
// For auth request
try {
const token = localstorage.getItem('token');
const res = await apiUrl.post(
'/authroute',
{
name: fullName,
originCountry: country,
career: careerStatus,
},
{
headers: { Authorization: `Bearer ${token}` },
}
);
const { data, status } = strapiRes;
if (Object.keys(data).length && status === 200) {
return res.status(status).json(data);
}
} catch (error) {
throw new Error(error);
}
// same for all request
apiUrl.get(endpoint);
apiUrl.post(endpoint, body);
apiUrl.put(endpoint, body);
apiUrl.delete(endpoint, body);

How can I prevent a componentDidMount from running, before my webservice call finishes

When app starts, SplashScreen comes. Behind splashScreen I want to get username and password from cache and then call webservice.
But when I get data from cache like AsyncStorage.getItem('myKey') which is in componentWillMount, it starts render. It doesn't let componentWillMount finish.
My Big problem is that componentDidMount starts before my controlallMeth methods finishes. Due to that, app crashes in that situation. How can I fix this issue?
Here is my code:
I get username and password from app cache and call webservice like this:
componentWillMount(){
AsyncStorage.getItem('myKey').then(value => {
let valuePrsed = JSON.parse(value);
if(valuePrsed.username != null && valuePrsed.password != null)
{
this.setState({username: valuePrsed.username, password: valuePrsed.password});
this.controlallMeth(); // call webservice
}
})
}
Here is method where I call webservice:
controlallMeth(){
let collection={}
collection.username = this.state.username,
collection.password = this.state.password
fetch('url', {
method: 'POST',
headers: new Headers({
Accept: 'application/json',
'Content-Type': 'application/json', // <-- Specifying the Content-Type
}),
body: JSON.stringify(collection) // <-- Post parameters
})
.then((response) => response.text())
.then(leaders => {
this.setState({PersonalInfo: leaders});
})
.catch((error) => {
console.error(error);
});
}
And here is componentDidMount
componentDidMount() {
StatusBar.setHidden(true);
this.setState({ fadeAnim: new Animated.Value(0) },
() => {
Animated.timing( // Animate over time
this.state.fadeAnim, // The animated value to drive
{
toValue: 1, // Animate to opacity: 1 (opaque)
duration: 3000,
}
).start(() => {
if(this.state.values != null)
{
console.log("go page1");
this.props.navigation.navigate('Page1',{datas: this.state.PersonalInfo});
}
else{
this.props.navigation.navigate('login');
}
})
}) // Starts the animation
}
Given that the componentWillMount is deprecated now, it's better not to use it. You can get your cached values inside constructor or componentDidMount method
constructor(props) {
super(props);
StatusBar.setHidden(true);
AsyncStorage.getItem('myKey').then(value => {
let valuePrsed = JSON.parse(value);
if(valuePrsed.username != null && valuePrsed.password != null)
{
this.setState({username: valuePrsed.username, password: valuePrsed.password});
this.controlAllMeth(); // call webservice
}
});
}
For making sure that the animateing and fetching method completely finish before going to other screen, you can use Promise.all:
controlAllMeth() {
Promise.all([this.callFetch(), this.startAnim()])
.then(([fetchResponse, animResponse]) => {
this.setState({PersonalInfo: fetchResponse.text()});
if(this.state.values != null)
{
console.log("go page1");
this.props.navigation.navigate('Page1',{datas: this.state.PersonalInfo});
}
else{
this.props.navigation.navigate('login');
}
})
.catch(err => {
});
}
callFetch() {
let collection={}
collection.username = this.state.username,
collection.password = this.state.password
return fetch(url, {
method: 'POST',
headers: new Headers({
Accept: 'application/json',
'Content-Type': 'application/json', // <-- Specifying the Content-Type
}),
body: JSON.stringify(collection) // <-- Post parameters
}
);
}
startAnim() {
return new Promise((resolve, reject) => {
this.setState({ fadeAnim: new Animated.Value(0) },
() => {
Animated.timing( // Animate over time
this.state.fadeAnim, // The animated value to drive
{
toValue: 1, // Animate to opacity: 1 (opaque)
duration: 3000,
}
).start(() => {
resolve();
})
}); // Starts the animation
});
}
You might wanna use async method here, as controlallMeth an async call. Making the whole process to wait making sure you do the fetch request then move on.
async componentWillMount(){
AsyncStorage.getItem('myKey').then(value => {
let valuePrsed = JSON.parse(value);
if(valuePrsed.username != null && valuePrsed.password != null)
{
this.setState({username: valuePrsed.username, password: valuePrsed.password});
await this.controlallMeth(); //I am assuming you did a typo here this.controlall();
}
})
}
controlallMeth = async() => {
let collection={}
collection.username = this.state.username,
collection.password = this.state.password
const res = await fetch('url', {
method: 'POST',
headers: new Headers({
Accept: 'application/json',
'Content-Type': 'application/json', // <-- Specifying the Content-Type
}),
body: JSON.stringify(collection) // <-- Post parameters
})
const leaders = await res.text();
this.setState({PersonalInfo: leaders});
}
Though it's not recommended to have async calls in componentWillMount so you might wanan switch to componentDidMount

React Native AsyncStorage: Get Token and Use it in a refactored API fetch

I have decided to put all my API calls in a seperate file and they are all stateless.
const get = endPoint => {
let token = "c8c17003468314909737ae7eccd83d4b6eecb792"; //I have put this token here manually
return fetch(endPoint, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Token " + token
}
}).then(response => response.json());
};
and in the same file i have the actual API calls. Example is as follows.
export const loadGroups = () => {
const endPoint = "https://xxxx.com/api/groups/";
return get(endPoint);
};
This works perfectly when i call the API from various components as follows.
import { loadGroups } from "../../api";
componentDidMount() {
loadGroups()
.then(responseJson => {
this.setState({
groups: responseJson
});
})
.catch(error => {
console.error(error);
});
}
However, I want to use AsyncStorage to retrieve a stored token and the due nature of it is to return a promise. This works well when i write the functions of getting the token and storing it in SetState in every component that I do the calls. I really want to refactor the code and using redux is a pain for me.
so far, i have written a file to get the token and it returns a promise.
import { AsyncStorage, Text } from "react-native";
const MyToken = async () => {
try {
const retrievedItem = await AsyncStorage.getItem("userToken");
const item = JSON.parse(retrievedItem);
return item;
} catch (error) {
return null;
}
};
export default MyToken;
And in the API file, I have re-written the code above to
const get = endPoint => {
MyToken().then(token => {
console.log(token, "try 1"); //this works
const lookupOptions = {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Token " + token
}
};
return fetch(endPoint, lookupOptions).then(response => {
console.log(response.json(), "promise response,json");
response.json();
});
});
};
However, whenever i call loadGroups().then() (like in the first example) function in any component, I get an errors that loadGroups.then() can't be resolved
Is there any way to resolve this without state, redux, mobx keeping in mind i want my API code in stateless functions in seperate modules.
In V2 of get function, you are not returning any Promise. Either put a return statement in get function like
const get = endPoint => {
return MyToken().then(
...
);
}
Or return Promise explicitly from that function, consider following code snippets
const get = endPoint => {
return new Promise((resolve, reject) => {
MyToken().then(token => {
...
fetch(endPoint, lookupOptions)
.then(response => response.json())
.then(resolvedResponse => {
resolve(resolvedResponse);
}).catch(error => {
reject(error);
});
});
});
};
Hope this will help!

Uncaught (in promise) {email: "email already exists"}

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;

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