I am building an app using react native that requires me to do multiple get request
on same API with token.
Let say the URL is like this:
Token URL = , API URL 1 =
and API URL 2 =
First of all, to fetch the data from either API URLs, I wrote it like this
Example for students_actions.js
import axios from 'axios';
import { FETCH_STUDENT } from './types';
const TOKEN_URL = '...'
const STUDENT_URL = '...'
export const fetchStudent = (callback) => async (dispatch) => {
axios.post(TOKEN_URL, {
email: 'email',
password: 'password',
role: 'user'
})
.then((response) => {
const accessToken = response.data.token;
//console.log(accessToken);
axios.get(STUDENT_URL, {
headers: { 'Authorization': 'Bearer '.concat(accessToken) }
})
.then((studentResponse) => {
dispatch({ type: FETCH_STUDENT, payload: studentResponse.data });
callback();
})
.catch((e) => {
console.log(e);
});
})
.catch((error) => {
console.log(error);
});
};
Example for students_reducers.js
import { FETCH_STUDENT } from '../actions/types';
const INITIAL_STATE = {
data: []
};
export default function (state = INITIAL_STATE, action) {
switch (action.type) {
case FETCH_STUDENT:
return action.payload;
default:
return state;
}
}
and call it inside render function like this
//some code
import { connect } from 'react-redux';
import * as actions from '../actions';
onButtonPressProfile = () => {
this.props.fetchStudent(() => {
this.props.navigation.navigate('Profile');
});
}
class StudentProfile extends Component {
render() {
return(
<View><Text>{this.props.students.name}</Text></View>
);
}
}
function mapStateToProps({ students }) {
return { students: students.data };
}
export default connect(mapStateToProps, actions)(StudentProfile);
While this is all running without any problem I feel like students_actions.js
can be further simplify by writing the code for retrieving the token in other file and call the value back inside students_actions.js
for GET request
.
The reason is so I do not have to request token everytime I want to access either students
or cars
. Lets say, I did request one time and I can use the same token for like 24 hours to access the API. Once it expired, then I have to do another request for token to access the API again.
I already wrote the code for token_actions.js
together with token_reducer.js
. Below are the two codes.
token_actions.js
//import library
// this code works
const TOKEN_URL = apiConfig.url + 'tokens';
const auth = {
email: 'email',
password: 'password',
role: 'user'
};
export const fetchToken = () => async (dispatch, getState) => {
axios.post(TOKEN_URL, auth)
.then((response) => {
dispatch({ type: FETCH_TOKEN, payload: response.data.token });
})
.catch((error) => {
console.log(error);
});
};
token_reducer.js
import {
FETCH_TOKEN
} from '../actions/types';
const INITIAL_STATE = {
data: []
};
export default function (state = INITIAL_STATE, action) {
switch (action.type) {
case FETCH_TOKEN:
return action.payload;
default:
return state;
}
}
students_actions.js
axios.get(STUDENT_URL, { headers: {
'Authorization': 'Bearer '.concat(here is the value from token_actions)}})
And now I am stuck at how should I call/import the payload from token_actions.js
into students_actions.js
? Should I use mapStateToProps
or is there any other way to do this?
Right now, this app does not have any authentication function yet. It is basically an app that shows the data fetched from API.
I wrote this app mainly based on examples I found online and for this case I found this example but seems not really what I want to achieve.
I do not really quite understand JavaScript so I will be really glad if anyone could pointed out any link related to this case or maybe same questions here on Stack Overflow and also maybe some suggestions.
I am building an app using react native that requires me to do multiple get request
on same API with token.
Let say the URL is like this:
Token URL = https://test.co/v1/tokens
, API URL 1 = https://test.co/v1/students
and API URL 2 = https://test.co/v1/cars
First of all, to fetch the data from either API URLs, I wrote it like this
Example for students_actions.js
import axios from 'axios';
import { FETCH_STUDENT } from './types';
const TOKEN_URL = '...'
const STUDENT_URL = '...'
export const fetchStudent = (callback) => async (dispatch) => {
axios.post(TOKEN_URL, {
email: 'email',
password: 'password',
role: 'user'
})
.then((response) => {
const accessToken = response.data.token;
//console.log(accessToken);
axios.get(STUDENT_URL, {
headers: { 'Authorization': 'Bearer '.concat(accessToken) }
})
.then((studentResponse) => {
dispatch({ type: FETCH_STUDENT, payload: studentResponse.data });
callback();
})
.catch((e) => {
console.log(e);
});
})
.catch((error) => {
console.log(error);
});
};
Example for students_reducers.js
import { FETCH_STUDENT } from '../actions/types';
const INITIAL_STATE = {
data: []
};
export default function (state = INITIAL_STATE, action) {
switch (action.type) {
case FETCH_STUDENT:
return action.payload;
default:
return state;
}
}
and call it inside render function like this
//some code
import { connect } from 'react-redux';
import * as actions from '../actions';
onButtonPressProfile = () => {
this.props.fetchStudent(() => {
this.props.navigation.navigate('Profile');
});
}
class StudentProfile extends Component {
render() {
return(
<View><Text>{this.props.students.name}</Text></View>
);
}
}
function mapStateToProps({ students }) {
return { students: students.data };
}
export default connect(mapStateToProps, actions)(StudentProfile);
While this is all running without any problem I feel like students_actions.js
can be further simplify by writing the code for retrieving the token in other file and call the value back inside students_actions.js
for GET request
.
The reason is so I do not have to request token everytime I want to access either students
or cars
. Lets say, I did request one time and I can use the same token for like 24 hours to access the API. Once it expired, then I have to do another request for token to access the API again.
I already wrote the code for token_actions.js
together with token_reducer.js
. Below are the two codes.
token_actions.js
//import library
// this code works
const TOKEN_URL = apiConfig.url + 'tokens';
const auth = {
email: 'email',
password: 'password',
role: 'user'
};
export const fetchToken = () => async (dispatch, getState) => {
axios.post(TOKEN_URL, auth)
.then((response) => {
dispatch({ type: FETCH_TOKEN, payload: response.data.token });
})
.catch((error) => {
console.log(error);
});
};
token_reducer.js
import {
FETCH_TOKEN
} from '../actions/types';
const INITIAL_STATE = {
data: []
};
export default function (state = INITIAL_STATE, action) {
switch (action.type) {
case FETCH_TOKEN:
return action.payload;
default:
return state;
}
}
students_actions.js
axios.get(STUDENT_URL, { headers: {
'Authorization': 'Bearer '.concat(here is the value from token_actions)}})
And now I am stuck at how should I call/import the payload from token_actions.js
into students_actions.js
? Should I use mapStateToProps
or is there any other way to do this?
Right now, this app does not have any authentication function yet. It is basically an app that shows the data fetched from API.
I wrote this app mainly based on examples I found online and for this case I found this example but seems not really what I want to achieve.
I do not really quite understand JavaScript so I will be really glad if anyone could pointed out any link related to this case or maybe same questions here on Stack Overflow and also maybe some suggestions.
Share Improve this question edited Oct 26, 2023 at 16:50 Brian Tompsett - 汤莱恩 5,89372 gold badges61 silver badges133 bronze badges asked Nov 15, 2017 at 8:34 FangFang 8444 gold badges17 silver badges34 bronze badges2 Answers
Reset to default 10I the logical thing to do would be to create something like an AuthReducer where you store your token and your refresh token. This is an example of my basic AuthReducer:
export const INITIAL_STATE = {
oAuthToken: '',
refreshToken: '',
};
export default AuthReducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case REFRESH_OAUTH_DATA:
const { oAuthToken, refreshToken } = action.payload;
return { ...state, oAuthToken, refreshToken };
case LOGOUT:
return INITIAL_STATE;
case LOGIN_FETCH_SUCCESS:
const { oAuthToken, refreshToken } = action.payload;
return { ...state, oAuthToken, refreshToken };
default:
return state;
}
};
Now you can get your token in your actions using the getState method doing something like:
export const fetchStudent = (callback) => async (dispatch, getState) => {
const token = getState().AuthReducer.oAuthToken;
....
};
Remember that if you are using ES6 you might also want to use await:
export const fetchStudent = (callback) => async (dispatch, getState) => {
try {
const accessToken = getState().AuthReducer.oAuthToken;
let response = await axios.get(STUDENT_URL, {
headers: { 'Authorization': 'Bearer '.concat(accessToken) }
})
dispatch({ type: FETCH_STUDENT, payload: response.data });
callback();
} catch(e) {
console.log(e);
}
};
This way your code is way easier to read and maintain.
There is a better (= simpler) approach without redux-thunk
at all, and without react-redux
additional hooks.
Just create and export your store
, and import it everywhere as usual, without using useStore
and useDispatch
.
Here you can just import store into your api layer and call something like store.getState().auth.token
before each request.
Some may say that this way you won't be able to test the app, but they would be wrong, you can mock this import easily, but even better you can just reset your store before each test without mocking and import it as usual.
You can do the same thing with dispatch
and remove redux-thunk
from the project. The code will be smaller, cleaner, faster.