I'm having trouble getting anything after an axios post to execute. The data posts to the backend as expected, but I can't get anything to run afterwards. Even a console.log after the post doesn't work. I've tried promise and async await based axios and I can't get anything after the post via axios to run. Any ideas what I'm doing wrong?
Create React App 3.3.0
React 16.11
React Router 5.1.2
import React, { Component } from 'react'
import { withRouter } from 'react-router'
import axios from 'axios'
...
class Contact extends Component {
...
submitContactHandler = async event => {
event.preventDefault()
try {
await axios.post('/mail/contact', {
userName: this.state.formData.name.value,
userEmail: this.state.formData.email.value,
userMessage: this.state.formData.message.value
})
this.props.history.push('/about')
console.log("This doesn't even run")
} catch (error) {
console.log(error)
}
}
render() {
...
return (
...
<Form onSubmit = {(event) => this.submitContactHandler(event)}>
...
</Form >
...
)
}
}
export default withRouter(Contact)
Handle the response from backend
await axios.post('/mail/contact', {
userName: this.state.formData.name.value,
userEmail: this.state.formData.email.value,
userMessage: this.state.formData.message.value
})
.then((response) => {
this.props.history.push('/about')
}, (error) => {
console.log(error);
});
Related
I am working on user registration setup and stuck on a problem where I am not able to redirect from a page 'localhost:3000/activate/tokenNo.'(Activation.jsx file) on load to my main page (App.jsx file) .
Here is my activation.jsx file :
import React, { useEffect } from 'react';
import { useNavigate } from "react-router-dom";
const Activate = () => {
const navigate = useNavigate();
useEffect(() => {
navigate('/')
}, [navigate])
return (
<div>Activation Page</div>
)
}
export default Activate;
Here is my App.jsx file :
import React from 'react';
export const App = () => {
return <div>Dashboard</div>;
};
export default App ;
My activationController.js file :
exports.activationController = (req,res) => {
const {token} = req.body
if(token){
//Verify the token is valid or not or expired
jwt.verify(token , process.env.JWT_ACCOUNT_ACTIVATION ,
(err , decoded) => {
if(err){
return res.status(401).json({
error: "Expired Token , Signup again"
})
}
else{
//if valid save to database
//Get name email password from token
const {name , email , password} = jwt.decode(token)
const user = new User({
name ,
email ,
passsword
})
user.save((err,user) => {
if(err){
return res.status(401).json({
error: errorHandler(err)
})
}
else{
return res.json({
success: true ,
message: "Signup successful",
user
})
}
})
}
})
}
else{
return res.json({
message: "error happening please try again"
})
}
}
In my auth.routes.js
router.post('/activation', activationController)
I recieved an error in my console --> index.tsx:25 No routes matched location "/activate/tokenNo."
My reference folder --> https://github.com/Mohammed-Abdelhady/FULL-MERN-AUTH-Boilerplate
You may need "Navigate( to="where to go") instead. Leaving the dependencies open in useEffect will make the code run only once at load time. If you include [navigate] it will run every time. Not sure what you are trying to achieve, but Router/Routes/Route may be a better mechanism. If you are doing login/registration, in your login you would have a Link to your registration page. Then you could setup 2 routes, one for Login and one for Registration.
import React, { useEffect } from 'react';
import { Navigate } from "react-router-dom";
const Activate = () => {
useEffect(() => {
Navigate( to='/');
}, [])
return (
<div>Activation Page</div>
)
}
export default Activate;
Often we require to perform some extra action on component or page render initially.
Like, Data fetching, etc.
To implement like this we can use the useEffect hook from react and state our execution into it.
I can't see the useNavigate hook in the latest version of react-router-dom so we can use the useHistory hook.
For Example:
import React, { useEffect } from "react"
import { useHistory } from 'react-router-dom'
const App = () => {
const history = useHistory();
useEffect(() => {
history.push('Page2URL')
}, [history])
return (
<div>Page1</div>
)
}
Greetings Javascript Developers. I'm stuck in a complex situation now where I need to access a function inside one of my functinal components outside in a normal js file.
Ok So here's what I'm doing: This is my Authorizer.js functional Component.
import React, { createContext, useState, useEffect, useContext } from "react";
import SplashScreen from "react-native-splash-screen";
import { useStore } from "../config/Store";
import { useDatabase } from "../config/Persistence";
import { getSessionCredentials } from "../config/Persistence";
import NavigationDrawer from "./NavigationDrawer";
import AuthStacks from "./AuthStacks";
const AuthContext = createContext();
export const useAuthorization = () => useContext(AuthContext);
export function Authorizer() {
//TODO check whether user is already signed in or not.
const realm = useDatabase();
const { state, dispatch } = useStore();
const [isAuthorized, setAuthorization] = useState(false);
useEffect(() => {
VerifyCredentials();
}, []);
async function VerifyCredentials() {
//TODO Check from Async Storage?
var session = await getSessionCredentials();
console.log("saved session", session);
if (session) {
await DispatchShopData();
await setAuthorization(true);
} else {
await setAuthorization(false);
}
sleep(1000).then(() => {
SplashScreen.hide();
});
}
async function DispatchShopData() {
try {
let shop = await realm.objects("Shop");
await dispatch({ type: "UPDATE_SHOP_DETAILS", payload: shop[0] });
} catch (error) {
console.log("failed to retrieve shop object", error);
}
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
return (
<AuthContext.Provider value={{ setAuthorization }}>
{isAuthorized ? <NavigationDrawer /> : <AuthStacks />}
</AuthContext.Provider>
);
}
This component basically handles my Authentication Flow, whether to show the Navigation Drawer or the Login Screen. Now I have another simple javascript file ApiService.js which does not have any components, only simple js functions.
import Axios from "axios";
import { getAuthToken } from "../config/Persistence";
import { LogoutUser } from "../config/Persistence";
import { Alert } from "react-native";
const BASE_URL = "#########################";
/** Defined my Api Endpoints Here */
let service = Axios.create({
baseURL: BASE_URL,
timeout: 10000,
});
service.interceptors.response.use((response) => {
console.log("[API] response intercepted data", response.data.message);
if (!response.data.status && response.data.tokenExpired) {
//Auth token has Expired. Show user Alert for Session Expired & redirect to login screen.
Alert.alert(
"Your Session has Expired!",
"Don't worry though. You just need to login again & you're set.",
[
{
text: "Continue",
style: "default",
onPress: () => {
LogoutUser()
.then((success) => {
if (success) {
//TODO Find a way to Access this function from Authorizer.js Component.
//setAuthorization(false);
}
})
.catch((error) => {
console.log("failed to logout after session expiry", error);
});
},
},
]
);
}
return response;
});
/** Defined my other api functions called inside my other components */
function TestSampleApi() {
try {
return new Promise(async function (resolve, reject) {
const response = await service.get("https://jsonplaceholder.typicode.com/users");
if (response.data != null) {
resolve(response.data);
} else {
reject(response.status);
}
});
} catch (error) {
console.log("request error", error.message);
}
}
export {
TestSampleApi,
/** Exporting other api functions as well */
};
In my ApiService.js file, I've setup a response interceptors whose job is to catch the default auth token expired response and SignOut user immediately and take him to the Login Screen. Here's now where my issue comes.
In normal scenarios, where I need to access functions from one component inside another component, I can manage is using CreateContext() and useContent() hooks. However, how do I access the useState function setAuthorization in my Authorizer.js components in my ApiService.js file as a normal js function.
I only need to call setAuthorization(false) from my response interceptor block to make the user return to the Login Screen. Problem is idk how to access that state setter function. So any help would be greatly appreciated.
I am using axios in my create-react-app. Which is the best way to use axios:
Method 1:
ajax.js
import axios from 'axios';
const axiosInstance = axios.create({});
export default axiosInstance;
app.js
import ajax from './ajax.js';
ajax.post('url');
Method 2:
ajax.js
import axios from 'axios';
class AjaxService{
constructor(apiConfig){
this.service = axios.create(apiConfig);
}
doGet(config){
return this.service.get(config.url);
}
...
}
export default AjaxService;
app.js:
import AjaxService from './ajax';
const service1 = new AjaxService();
service.doGet({url:'url'});
app2.js
import AjaxService from './ajax';
const service2 = new AjaxService();
service.doGet({url:'url'});
In method 2, we have to initialize the service wherever we make a call, which may or may not be a best practice. If we follow method 2, Is there a way to make it as a common service across the application?
i've seen a way in here and i came up with another solution like i explained below:
1 - i created my service with axios
import axios from 'axios';
const instance = axios.create({
baseURL: process.env.REACT_APP_BASE_URL
// headers: { 'X-Custom-Header': 'foobar' }
});
// Add a request interceptor
instance.interceptors.request.use(
(config) => {
// Do something before request is sent
return config;
},
(error) => {
// Do something with request error
return Promise.reject(error);
}
);
// Add a response interceptor
instance.interceptors.response.use(
(response) => {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
},
(error) => {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
}
);
export default instance;
2- i use that service to create a function for api call.
in here i can add a new AbortController for later use in useEffect.
import axios from 'services/request';
export function getMarket(type, callBack) {
const controller = new AbortController();
axios
.get(`https://dev.zh1.app/api/market/map?type=${type}`, {
signal: controller.signal
})
.then((res) => {
callBack(true, res.data);
})
.catch((res) => {
callBack(false, res.response);
});
return controller;
}
export default {
getMarket
};
3- in the hooks folder i created a hook called useApi. the controller from step 2 used in here. if you check the link above you can see the author add request function because you may have some props to pass to api call. i think it is valid but ugly. so i decided to create a closure for useApi to pass any params i want to the Axios in step 2.
import { useEffect, useState } from 'react';
// in useStrict mode useEffect call twice but will not in production
export default function useApi(apiFunc) {
return function useApiCall(...params) {
const [result, setResult] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const apiCall = useCallback(() => {
setLoading(true);
// controller is new AbortController which set each api function
const controller = apiFunc(...params, (ok, data) => {
setLoading(false);
if (ok) {
setResult(data);
} else {
setError(data.message);
}
});
return () => {
controller.abort();
};
}, []);
useEffect(() => {
apiCall();
}, []);
return {result, loading, error, [apiFunc.name]: apiCall};
};
}
4- finally in my react component
import { IconButton } from '#mui/material';
import useApi from '#share/hooks/useApi';
import { Refresh } from '#share/icons';
import { getCaptcha as CaptchaApi } from 'api/oauth/captcha';
import CaptchaStyle from './style';
export default function Captcha() {
const { result: captcha, getCaptcha } = useApi(CaptchaApi)();
return (
<CaptchaStyle>
<img src={`data:image/png;base64,${captcha?.base64}`} alt="captcha" />
<IconButton onClick={getCaptcha}>
<Refresh />
</IconButton>
</CaptchaStyle>
);
}
i think this approach i quite good and if you dont need to pass any props just call useApi([yourfunction])() with empty function.
and you can have access to the function inside of useApi if you need to call it again.
It totally depends on your project. If your project relies more on the function component then go ahead and use the first approach.
If you use classes for the majority of your components go for the second approach.
I generally use the first approach, it's easy and avoids this altogether. Also, it's easy to target multiple instances.
// Ajax.js file
import axios from "axios";
export function updateData=(body,callback){
le url= 'your api to call'
axios
.put(url, body)
.then((response) => response.data)
.then((res) => {
callback(res);
})
.catch((error) => {
console.log(error);
callback('error occurred');
});
}
// app.js file
import {updateData} from './ajax.js'
//Place your code where you need
updateData(yourBodyToPass,res=>{
//Stuff after the response
)
Note:- pass your data as first argument and get response of api from second
I'm trying to include a reset password functionality using firebase in my react-redux login page, however I seem a bit lost.
I included the code below in my userActions.js and also installed firebase on the client-side.
export const resetPassword = email => async dispatch => {
try {
firebase
.auth()
.sendPasswordResetEmail(email)
.then(() =>
dispatch({
type: RESET_SUCCESS,
payload: "Reset email sent. Go check your inbox."
})
)
.catch(err => {
dispatch({
type: RESET_ERROR,
payload: "...some message for the user..."
});
});
} catch (err) {
dispatch({
type: RESET_ERROR,
payload: "...some message for the user..."
});
}
};
In my types.js, I included this as well
export const RESET_SUCCESS = "RESET_SUCCESS";
export const RESET_ERROR = "RESET_ERROR";
I've imported the resetPassword in my login page as well
import { resetPassword } from "../redux/actions/userActions";
My question is that... how can I add the resetPassword I imported to a button called 'Reset Password'? N/B: I used the handleSubmit for user login functionality. I'm also using form from Material UI for my login functionality. I'm a react newbie, I'd really appreciate if someone puts me through
Assuming your resetPassword function works correctly. You can use it in your react component like this:
import React, { Component } from 'react';
import { Buttton } from 'material-ui';
import { resetPassword } from '../redux/actions/userActions';
class Example extends Component {
state = { loading: false };
handleReset = async () => {
const { email, dispatch } = this.props;
this.setState({ loading: true });
await resetPassword(email)(dispatch);
// message or alert you want to display
this.setState({ loading: false });
};
render() {
return (
<Buttton loading={this.state.loading} onClick={this.handleReset}>
Reset Password
</Buttton>
);
}
}
export default connect()(Example);
I'm working on a login form in a project with React, Redux and Redux-Thunk. Using Redux-Thunk, I'm able to dispatch async actions like delivering the submitted login form to the back-end and bringing back validated data back to the state via reducers. Once the component gets the data it needs, it can then redirect to the page it needs without a problem.
The issue is, right before redirecting the user I need to write some data which came from asynchronous network request to the localStorage. If I don't do this async, the user gets redirected with the initial state values written to the local storage.
As a solution, I'm using promises and timeouts right in the React component to wait for the incoming data.
This approach seems to work but it doesn't feel right, can someone suggest me a better practice?
Here's the code in the component, I filtered most of the irrelevant things to make it as short as possible here.
import React, {Component} from 'react';
import {bindActionCreators} from 'redux';
import {browserHistory} from 'react-router';
import {reduxForm} from 'redux-form';
import {connect} from 'react-redux';
import {validate} from './../utils/login/surfaceValidation';
import {inputAlerts} from './../utils/login/inputAlerts';
import {submitLogin} from './../redux/actions/index';
class Form extends Component {
componentWillReceiveProps(nextProps) {
if(nextProps.loginApproved) {
this.handleValidLogin();
}
}
handleLogin(props) {
this.props.submitLogin(props);
// submitLogin is async action handled by redux-thunk it returns
// this.props.loginApproved and if it's true componentWillReceiveProps
// will trigger.
}
handleValidLogin() {
this.writeToStorage()
.then(() => {
browserHistory.push('/main');
}).catch((err) => {
console.log(err);
});
}
writeToStorage(){
return new Promise((resolve, reject) => {
setTimeout(() =>{
localStorage.setItem('user',
JSON.stringify({
authenticated: true,
username: this.props.username,
id: this.props.id,
token: this.props.token
}));
}, 3000);
setTimeout(() => {
if(this.props.token != null) {
resolve();
console.log('got a token - resolving.');
} else {
reject();
console.log('no token - rejecting. ');
}
}, 4000);
});
}
render() {
return (
// Login form component is here.
// When user submits form, this.handleLogin() is called.
);
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({submitLogin});
}
function mapStateToProps(state) {
return {
loginApproved: state.login.loginApproved,
username: state.login.username,
id: state.login.id,
token: state.login.token
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Form);
As far as I know localStorage.seItem is synchronous so you can call function saving data to storage before redirecting.