如何将异步 thunk 操作延迟到存储身份验证会话令牌之后?
How do you delay an async thunk action until after authentication session token has been stored?
我已经构建了一个 API,我正在尝试获取数据(使用 axios)并将其呈现到我的 react-native 应用程序(node/express 服务器)中的一个组件中。我正在使用 JWT 来验证我的用户和屏幕路由的反应导航。
我已成功验证会话令牌并将其存储到 AsyncStorage 中。登录后,应用程序导航到第一个屏幕,我想在其中显示我的 API.
中的数据列表
问题是在将令牌保存到 AsyncStorage 之前正在执行 GET 请求,因此我收到 401 未经授权的错误。
执行应该是-
1) 验证用户
2) 使用获取的数据渲染组件
啊啊!我想不通。请帮忙? :(
我尝试调用生命周期方法 componentDidMount 中的操作,但没有成功。
这是父组件:
class PlansScreen extends Component {
static navigationOptions = ({ navigation }) => ({
tabBarLabel: 'Plans',
tabBarIcon: ({ tintColor }) => (
<Icon name="schedule" size={30} color={tintColor} />
)
});
render() {
return (
<View>
<ActivityList/>
</View>
);
}
}
export default PlansScreen;
这是我要呈现获取数据列表的子组件:
忽略我还没有充实整个组件的事实,我目前正试图在会话令牌保存后执行 API 请求
class ActivityList extends Component {
componentDidMount() {
this.props.fetchActivities();
}
render() {
// console.log(this.props);
return (
<View>
<FlatList
//My data will render here
/>
</View>
);
}
}
export default connect(null, {
fetchActivities,
})(ActivityList);
这是 fetchActivities thunk 动作创建者 -
export const fetchActivities = () => {
return async (dispatch) => {
try {
dispatch({ type: FETCH_ACTIVITIES_INITIATE });
let token = await AsyncStorage.getItem('token');
let { data } = await axios.get(`${ROOT_URL}/activities`);
dispatch({
type: FETCH_ACTIVITIES_SUCCESS,
payload: data
});
console.log(data);
} catch(error) {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
console.log(error.request);
} else {
console.log('Error', error.message);
}
console.log(error.config);
// signupUserFail(dispatch);
};
};
};
这是我的 activity 列表缩减器 -
import {
FETCH_ACTIVITIES_INITIATE,
FETCH_ACTIVITIES_SUCCESS
} from '../actions/types';
const INITIAL_STATE = {
activities: null,
loading: false
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case FETCH_ACTIVITIES_INITIATE:
return { ...state, loading: true };
case FETCH_ACTIVITIES_SUCCESS:
return {...state,
activities: action.payload,
loading: false
};
default:
return state;
}
};
这是我的 authentication/login thunk 动作创建者 -
export const loginUser = ({ userEmail, userPassword, navigation }) => {
return async (dispatch) => {
try {
dispatch({ type: LOGIN_USER_INITIATE });
let { data } = await axios.post(`${ROOT_URL}/users/login`, {
userEmail, userPassword
});
AsyncStorage.setItem('token', data.token);
// AsyncStorage.getItem('token').then((res) => console.log(res));
dispatch({
type: LOGIN_USER_SUCCESS,
payload: data
});
navigation.navigate('Plans');
console.log(data);
// console.log(store.getState());
} catch(error) {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
console.log(error.request);
} else {
console.log('Error', error.message);
}
// console.log(error.config);
loginUserFail(dispatch);
};
};
};
这是我的 login/auth reducer -
const INITIAL_STATE = {
userName: '',
userEmail: '',
userPassword: '',
user: null,
loginError: '',
signupError: '',
loading: false
};
export default (state = INITIAL_STATE, action) => {
// console.log(action);
switch (action.type) {
case USERNAME_CHANGED:
return {...state, userName: action.payload};
case EMAIL_CHANGED:
return {...state, userEmail: action.payload};
case PASSWORD_CHANGED:
return {...state, userPassword: action.payload};
case LOGIN_USER_INITIATE:
return {...state, loading: true, loginError: '', signupError: ''};
case SIGNUP_USER_INITIATE:
return {...state, loading: true, loginError: '', signupError: ''};
case LOGIN_USER_SUCCESS:
return { ...state,
user: action.payload,
loginError: '',
signupError: '',
loading: false,
userPassword: '',
userEmail: ''
};
case LOGIN_USER_FAIL:
return { ...state, loginError: 'Authentication failed!', userPassword: '', loading: false };
case SIGNUP_USER_FAIL:
return { ...state, signupError: 'Signup failed!', userPassword: '', loading: false };
default:
return state;
}
};
this.props.fetchActivities 在保存令牌之前正在调用!
几个小时以来我一直在努力解决这个问题!!非常感谢任何帮助,即使只是引导我朝着正确的方向前进。
哇...我弄清楚我做错了什么,我觉得很可笑,因为我没有早点意识到 x_x 我忘了在 GET 请求中添加 auth header,这就是为什么它不是正在验证。
在 fetchActivities 动作创建器中,对我来说应该是 -
let { data } = await axios.get(`${ROOT_URL}/activities`, {
headers: { 'x-auth': `${token}` }
});
对于以后阅读本文的任何人 ----- 请确保您添加了您的身份验证 header。感谢@Oblosys 的回复,这让我意识到它与保存令牌的时间无关。
我已经构建了一个 API,我正在尝试获取数据(使用 axios)并将其呈现到我的 react-native 应用程序(node/express 服务器)中的一个组件中。我正在使用 JWT 来验证我的用户和屏幕路由的反应导航。
我已成功验证会话令牌并将其存储到 AsyncStorage 中。登录后,应用程序导航到第一个屏幕,我想在其中显示我的 API.
中的数据列表问题是在将令牌保存到 AsyncStorage 之前正在执行 GET 请求,因此我收到 401 未经授权的错误。
执行应该是-
1) 验证用户 2) 使用获取的数据渲染组件
啊啊!我想不通。请帮忙? :(
我尝试调用生命周期方法 componentDidMount 中的操作,但没有成功。
这是父组件:
class PlansScreen extends Component {
static navigationOptions = ({ navigation }) => ({
tabBarLabel: 'Plans',
tabBarIcon: ({ tintColor }) => (
<Icon name="schedule" size={30} color={tintColor} />
)
});
render() {
return (
<View>
<ActivityList/>
</View>
);
}
}
export default PlansScreen;
这是我要呈现获取数据列表的子组件: 忽略我还没有充实整个组件的事实,我目前正试图在会话令牌保存后执行 API 请求
class ActivityList extends Component {
componentDidMount() {
this.props.fetchActivities();
}
render() {
// console.log(this.props);
return (
<View>
<FlatList
//My data will render here
/>
</View>
);
}
}
export default connect(null, {
fetchActivities,
})(ActivityList);
这是 fetchActivities thunk 动作创建者 -
export const fetchActivities = () => {
return async (dispatch) => {
try {
dispatch({ type: FETCH_ACTIVITIES_INITIATE });
let token = await AsyncStorage.getItem('token');
let { data } = await axios.get(`${ROOT_URL}/activities`);
dispatch({
type: FETCH_ACTIVITIES_SUCCESS,
payload: data
});
console.log(data);
} catch(error) {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
console.log(error.request);
} else {
console.log('Error', error.message);
}
console.log(error.config);
// signupUserFail(dispatch);
};
};
};
这是我的 activity 列表缩减器 -
import {
FETCH_ACTIVITIES_INITIATE,
FETCH_ACTIVITIES_SUCCESS
} from '../actions/types';
const INITIAL_STATE = {
activities: null,
loading: false
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case FETCH_ACTIVITIES_INITIATE:
return { ...state, loading: true };
case FETCH_ACTIVITIES_SUCCESS:
return {...state,
activities: action.payload,
loading: false
};
default:
return state;
}
};
这是我的 authentication/login thunk 动作创建者 -
export const loginUser = ({ userEmail, userPassword, navigation }) => {
return async (dispatch) => {
try {
dispatch({ type: LOGIN_USER_INITIATE });
let { data } = await axios.post(`${ROOT_URL}/users/login`, {
userEmail, userPassword
});
AsyncStorage.setItem('token', data.token);
// AsyncStorage.getItem('token').then((res) => console.log(res));
dispatch({
type: LOGIN_USER_SUCCESS,
payload: data
});
navigation.navigate('Plans');
console.log(data);
// console.log(store.getState());
} catch(error) {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
console.log(error.request);
} else {
console.log('Error', error.message);
}
// console.log(error.config);
loginUserFail(dispatch);
};
};
};
这是我的 login/auth reducer -
const INITIAL_STATE = {
userName: '',
userEmail: '',
userPassword: '',
user: null,
loginError: '',
signupError: '',
loading: false
};
export default (state = INITIAL_STATE, action) => {
// console.log(action);
switch (action.type) {
case USERNAME_CHANGED:
return {...state, userName: action.payload};
case EMAIL_CHANGED:
return {...state, userEmail: action.payload};
case PASSWORD_CHANGED:
return {...state, userPassword: action.payload};
case LOGIN_USER_INITIATE:
return {...state, loading: true, loginError: '', signupError: ''};
case SIGNUP_USER_INITIATE:
return {...state, loading: true, loginError: '', signupError: ''};
case LOGIN_USER_SUCCESS:
return { ...state,
user: action.payload,
loginError: '',
signupError: '',
loading: false,
userPassword: '',
userEmail: ''
};
case LOGIN_USER_FAIL:
return { ...state, loginError: 'Authentication failed!', userPassword: '', loading: false };
case SIGNUP_USER_FAIL:
return { ...state, signupError: 'Signup failed!', userPassword: '', loading: false };
default:
return state;
}
};
this.props.fetchActivities 在保存令牌之前正在调用!
几个小时以来我一直在努力解决这个问题!!非常感谢任何帮助,即使只是引导我朝着正确的方向前进。
哇...我弄清楚我做错了什么,我觉得很可笑,因为我没有早点意识到 x_x 我忘了在 GET 请求中添加 auth header,这就是为什么它不是正在验证。
在 fetchActivities 动作创建器中,对我来说应该是 -
let { data } = await axios.get(`${ROOT_URL}/activities`, {
headers: { 'x-auth': `${token}` }
});
对于以后阅读本文的任何人 ----- 请确保您添加了您的身份验证 header。感谢@Oblosys 的回复,这让我意识到它与保存令牌的时间无关。