I have a class API with a function which I wish to call in my component.
export default function(authentification){
axios.post('/login',params)
.then(response=> {
localStorage.setItem(ACCESS_TOKEN, response.headers.authorization);
localStorage.setItem(IS_AUTHENTICATED, true);
this.setState({isAuthenticated:true});
})
.catch(error =>{
const statusCode = error.response.status;
if(statusCode === 401)
errors.authentification = true;
else if (statusCode === 404)
errors.resource = true;
else
errors.server = true;
this.setState({errors});
});
}
I do not arrive in found how to call this function in my component and as to get back its result to put it in setState
First: separate your setState from your api helper method like:
export default function(authentification){
axios.post('/login',params)
.then(response=> {
localStorage.setItem(ACCESS_TOKEN, response.headers.authorization);
localStorage.setItem(IS_AUTHENTICATED, true);
return {status: "ok"}
})
.catch(error =>{
const statusCode = error.response.status;
if(statusCode === 401)
errors.authentification = true;
else if (statusCode === 404)
errors.resource = true;
else
errors.server = true;
return {status: "error", errors}
});
}
Or if you want to use a async/await syntax in your api method:
const authentification = async (params) => {
const response = await axios.post('/login',params);
const statusCode = response.status;
if (statusCode >= 200 && statusCode < 300) {
localStorage.setItem(ACCESS_TOKEN, response.headers.authorization);
localStorage.setItem(IS_AUTHENTICATED, true);
return {status: "ok"}
}
let errors = {};
if (statusCode === 401) {
errors.authentification = true;
}
else if (statusCode === 404) {
errors.resource = true;
}
else {
errors.server = true;
}
return {status: "error", errors}
}
export default authentification;
Then call you api function inside of componentDidMount() lifecycle method of your Component like:
...
componentDidMount = async () => {
let resp = await helperfunction();
if (resp.status === "ok") {
this.setState({isAuthenticated:true});
return;
}
this.setState({resp.errors});
}
...
in a file.js create all function you want and export it
let xxx = (authentification) => {
axios.post('/login',params)
.then(response=> {
localStorage.setItem(ACCESS_TOKEN, response.headers.authorization);
localStorage.setItem(IS_AUTHENTICATED, true);
this.setState({isAuthenticated:true});
})
.catch(error =>{
const statusCode = error.response.status;
if(statusCode === 401)
errors.authentification = true;
else if (statusCode === 404)
errors.resource = true;
else
errors.server = true;
this.setState({errors});
});
}
export default xxx;
then import it where you wanna use it like so --> import xxx from 'path';
I restructured my code. I do not know if it is the good architecture to employee. But I does not obtain answer in my component yet
Classe AuthentificationAPI :
import axios from "axios";
const AuthentificationAPI = {
login(params){
return axios.post('/login',params);
},
}
export {AuthentificationAPI as default}
AuthentificationService :
import { ACCESS_TOKEN, IS_AUTHENTICATED } from "constants/constants.js";
import AuthentificationAPI from "api//authentificationAPI.js";
const AuthentificationService = {
login(params){
let errors = {};
AuthentificationAPI.login(params).then(response => {
localStorage.setItem(ACCESS_TOKEN, response.headers.authorization);
localStorage.setItem(IS_AUTHENTICATED, true);
return {isAuthenticated:true};
})
.catch(error => {
const statusCode = error.response.status;
if(statusCode === 401)
errors.authentification = true;
else if (statusCode === 404)
errors.resource = true;
else
errors.server = true;
return errors;
});
},
}
export {AuthentificationService as default}
Call in my component :
let resp = AuthentificationService.login(params);
console.log(resp);
Related
I am working on a react app and I use tokens and refresh tokens for authentication. Whenever the backend returns a 401, the axios.interceptors.response picks it up and tries to refresh my token. If it succeeds, it will reinitiate the original call with the updated headers. See the code below:
// To avoid infinite loops on 401 responses
let refresh = false;
axios.interceptors.response.use(
(resp) => resp,
async (error) => {
if (error.response.status === 401 && !refresh) {
refresh = true;
const response = await axios.post(
"/api/auth/refresh",
{},
{ withCredentials: true }
);
if (response.status === 200) {
axios.defaults.headers.common[
"Authorization"
] = `Bearer ${response.data["accessToken"]}`;
return axios(error.config);
}
}
refresh = false;
return error.response;
}
);
This by itself works great, but not in combination with the code below in one of my components:
const [pages, setPages] = useState();
const [error, setError] = useState();
const navigate = useNavigate();
useEffect(() => {
async function fetchInfo() {
const response = await getMyPages();
if (response.status === 200) {
setPages(response.data);
}
else if (response.status === 401) {
setError(t("error.notAuthorized"));
navigate(`/login`, { replace: true });
}
// Any other error
else {
setError(t("error.unexpected"));
}
}
fetchInfo();
}, [t, navigate]);
// getMyPages function
export async function getMyPages() {
try {
const result = await axios.get(`/api/user/mypages`);
return result;
} catch (err) {
return err.response;
}
}
The problem is that the user is navigated to /login before the new request (with refreshed token) is made and finished. So when the new request finishes, I am not in the original component anymore and I can no longer update the pages state.
Any suggestions on how to handle this?
useEffect(() => {
let isMounted = true;
const controller = new AbortController();
const getMyPages = async () => {
try {
const response = await axios.get(`/api/user/mypages`, {
signal: controller.signal
});
isMounted && setPages(response.data);
} catch (err) {
navigate(`/login`, { replace: true });
}
}
getMyPages();
return () => {
isMounted = false;
controller.abort();
}
}, [])
My code:
let xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log(xhr.responseText)
}else if (xhr.status===404){
console.log('Not found!')
}
}
}
xhr.addEventListener('progress',()=>{
console.log("Progressing")
})
xhr.onprogress=()=>{
console.log("Progressing")
}
xhr.open('GET', 'msg.txt', false)
xhr.send()
I tried 2 method for onprogress:
xhr.addEventListener('progress',()=>{
console.log("Progressing")
})
xhr.onprogress=()=>{
console.log("Progressing")
}
anyone not worked
osjdsdmskmdsddknsdnskdnkjsdnfjknsdkjfnkjdsnfknsdjfnkdsnfkjdsnfkndksjfnkjdnfkndnfsdsdsdsdsdsdsdsdsdsdsdsdfsdf
useEffect(() => {
const cont = async () => {
const { status } = await Contacts.requestPermissionsAsync();
if (status === 'granted') {
const { data } = await Contacts.getContactsAsync({
fields: [Contacts.Fields.Emails],
});
if (data.length > 0) {
const contact = data[0];
console.log(contact);
}
}
}();
}, []);
please help im relatively new to typescript and im not sure why this error is occuring
You invoke the function like this:
(() => {
const { status } = await Contacts.requestPermissionsAsync();
if (status === 'granted') {
const { data } = await Contacts.getContactsAsync({
fields: [Contacts.Fields.Emails],
});
if (data.length > 0) {
const contact = data[0];
console.log(contact);
}
}
})();
I need to transfer status from the server to the client if I receive status 200 without content for getMainPage request. How can i do this?
I tried (example from google):
if (ctx.res) ctx.res.statusCode = 404;
return {notFound: true};
ctx.res always = undefined
/main page.ts/
IndexPage.getInitialProps = async (ctx: IExtendedAppContext): Promise<IPageProps> => {
const { reduxStore } = ctx;
const regionId = reduxStore.getState().regions.current?.id;
const cityId = reduxStore.getState().regions.current?.city;
const transaction = apm?.startTransaction('IndexPage');
const main: IMain = await reduxStore.dispatch(getMainPage({ region: regionId, city: cityId }, transaction));
const span = startSpan('fetchAlphabetList', transaction);
const alphabetList = await alphabetListService.fetch({ region: regionId, city: cityId })
.finally(() => endSpan(span));
endTransaction(transaction);
return { pageMeta: main.page_meta, alphabetList };
};
/with-redux-store.tsx/
export type Store = ReturnType<typeof getOrCreateStore>;
interface IProps {
reduxStore: Store;
initialReduxState: Store;
}
export interface IExtendedAppContext extends NextPageContext {
reduxStore: Store;
}
export interface IInitialProps extends AppContext {
ctx: IExtendedAppContext;
}
getMainPage request and all get requests uses that get method
public async get(entity: string, query: object, pathVariables: string[] | number[] = [], cookies: string = '') {
const queryURI = makeURIParams(query);
const key = makeQueryKey(entity, query, pathVariables);
try {
const localCopy = await this.getLocalCopy(key);
return this.handleResponse(localCopy);
} catch (error) {
console.log(this.getUrlAPI(entity, queryURI, pathVariables));
return this.fetch(this.getUrlAPI(entity, queryURI, pathVariables), {headers: {...this.getCookies(cookies)}})
.then(this._httpHandler).then(async (dataJSON: any) => {
try {
const { meta = {} } = dataJSON;
meta.requestDate = getCurrentTime();
const { expire, date } = meta;
if (expire <= date) {
await this.purgeStorageByKey(key);
return dataJSON;
}
if (expire !== 0) await this.setLocalCopy(key, JSON.stringify(dataJSON));
return dataJSON;
} catch (error) {
console.log(this.getUrlAPI(entity, queryURI, pathVariables), error);
return null;
}
}).then(this.handleResponse).catch((error: Error) => {
console.log(this.getUrlAPI(entity, queryURI, pathVariables), error);
return null;
});
}
}
/method where we can get request's status/
private _httpHandler(response: Response): Promise<IResponse | null> {
return new Promise(async (resolve, reject) => {
if ((response.status >= 200 && response.status < 300) || response.status === 403) {
try {
const json = await response.json();
resolve({ requestUrl: response.url, responseHeaders: response?.headers, ...json });
} catch (_) {
resolve(null);
}
} else {
reject(response.statusText);
}
});
}
so if it is async function and returns value, you can check status,
let mainResponseStatus = false;
if (main.status === 200) {
mainResponseStatus = true;
}
and then continue your code and return whatever you want but defense it in return
return {
somethingToReturn: mainResponseStatus ? returnWhatYouWant : []
}
Part of my component code where in componentDidMount calling tableList function from actions the code also below.
Originating a error in calling this.props.tableList is not a function, don't know why since connect second param mapDispatchToProps is returning bindActionCreators that bind the action tableList to this component by connect, and any help would be much appreciated.
SOLVED changed: export default connect(null, mapDispatchToProps)(CreateGenericTable) to const CreateGenericTableRedux = connect(null, mapDispatchToProps)(CreateGenericTable) and it started to work fine.
import { bindActionCreators } from 'redux';
import { tableList } from '../../actions/index.js'
class CreateGenericTable extends Component {
constructor(props){
super(props);
//const {dispatch} = props;
this.state = { rows:null, columns:null, idselected:null, view:null};
//this.handleClick.bind(this,id,this.props.editform)
}
componentDidMount(){
var token = getCookie('admin_session_token');
servicerequest = this.props.serviceRequest;
this.props.tableList(this.props.service,token,servicerequest,this.props.columns)
$.ajax({
type: "POST",
url: this.props.service,
crossDomain: true,
dataType: 'jsonp',
xhrFields: {
withCredentials: true
},
data: {
q: JSON.stringify({
[servicerequest]:{}
}),
admin_session_token:token,
},
success : (data) => {
var data = data[servicerequest];//var data = data['News_get'];
if(data.length>0){
var news_formated = [];
var listofkeys = Object.keys(data[0]);
for(var new_unformated of data){
var new_formated = [];
for(var key of listofkeys){
//console.log(key);
if(this.props.editform.indexOf('EditHeader') !== -1 && key.indexOf('language_items') !== -1){
new_formated['image'] = new_unformated[key][0]['image'];
new_formated['link'] = new_unformated[key][0]['link'];
}else{
if(this.props.editform.indexOf('EditNotification') !== -1){
if(key.indexOf('params') !== -1){
new_formated[key] = new_unformated[key]['message'];
}else{
new_formated[key] = new_unformated[key];
}
}else{
if(key.indexOf('active') !== -1){
if(new_unformated[key].indexOf('1') !== -1){
new_formated[key] = 'Yes';
}else{
new_formated[key] = 'No';
}
}else{
new_formated[key] = new_unformated[key];
}
}
}
}
news_formated.push(new_formated);
}
var columns_get = this.props.columns;//listofkeys;
return this.setState({rows:news_formated,columns:columns_get});
}else{
var columns_get = this.props.columns;
return this.setState({rows:null,columns:columns_get});
}
},
error: (xhr, status, err) =>{
////console.log('ups somehting went rong:'.err.toString());
},
});
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({ tableList }, dispatch);
}
export default connect(null, mapDispatchToProps)(CreateGenericTable)
------------------------------------------------------------------------------------actions------------------------------------
export const FETCH_TABLEDATA = 'FETCH_TABLEDATA'
export const EDIT_COMP = 'EDIT_COMP'
export function tableList(service,token,serviceRequest,columns){
var request = null;
$.ajax({
type: "POST",
url: service,
crossDomain: true,
dataType: 'jsonp',
xhrFields: {
withCredentials: true
},
data: {
q: JSON.stringify({
[servicerequest]:{}
}),
admin_session_token:token,
},
success : (data) => {
request = data;
},
error: (xhr, status, err) =>{
////console.log('ups somehting went rong:'.err.toString());
},
});
return {
type: FETCH_TABLEDATA,
payload: {request: request, serviceRequest: serviceRequest, columns: columns}
};
}
Reducer
import { FETCH_TABLEDATA } from '../actions/index.js'
//const INITIAL_STATE = {rows:null, columns:[]}
export default function(state = [], action){
switch(action.type){
case FETCH_TABLEDATA:
var new_formated = [];
var data = action.payload.request[action.payload.servicerequest];//var data = data['News_get'];
if(data.length>0){
var news_formated = [];
var listofkeys = Object.keys(data[0]);
for(var new_unformated of data){
for(var key of listofkeys){
//console.log(key);
if(this.props.editform.indexOf('EditHeader') !== -1 && key.indexOf('language_items') !== -1){
new_formated['image'] = new_unformated[key][0]['image'];
new_formated['link'] = new_unformated[key][0]['link'];
}else{
if(this.props.editform.indexOf('EditNotification') !== -1){
if(key.indexOf('params') !== -1){
new_formated[key] = new_unformated[key]['message'];
}else{
new_formated[key] = new_unformated[key];
}
}else{
if(key.indexOf('active') !== -1){
if(new_unformated[key].indexOf('1') !== -1){
new_formated[key] = 'Yes';
}else{
new_formated[key] = 'No';
}
}else{
new_formated[key] = new_unformated[key];
}
}
}
}
news_formated.push(new_formated);
}
return {rows:news_formated, columns:action.payload.columns};
}else{
return {rows:null, columns:action.payload.columns};
}
//{...state, {rows:null, columns:action.payload.columns}};
default:
return state;
}
}
Please check your mapDispatchToProps.
function mapDispatchToProps(dispatch){
return {
actions: bindActionCreators(actionsCreators, dispatch);
}
}
You can dispatch action like
this.props.actions.fn()
You are making API call(async operation) in your action. Please use redux-thunk for the same as after async operation you will have to make some state changes. This will take some time to mutate.