最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to use react-redux to store a token and use it on multiple axios request? - Stack Overflow

programmeradmin4浏览0评论

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 badges
Add a ment  | 

2 Answers 2

Reset to default 10

I 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.

发布评论

评论列表(0)

  1. 暂无评论