I am using react native for frontend and django for backend of my application, but I can't make an api request with axios to login authentication.
I would like to know why the request is not made to the backend but is rejected.
The code fails during the request, up to which point it is executed.
userSlice:
import axios from "axios";
import { createAsyncThunk, createSlice } from "#reduxjs/toolkit";
const initialState = {
isLoading:false,
isSuccess:false,
isError:false,
message:"",
userInfo: null
}
export const login = createAsyncThunk(
'user/login',
async (userData, thunkApi) => {
try{
const config = {
headers:{
'Content-type':'application/json'
}
}
const response = await axios.post(
'http://127.0.0.1:8000/api/users/login/',
userData,
config
)
return response.data
}catch(error){
return thunkApi.rejectWithValue(error.response?.data)
}
})
const userSlice = createSlice({
name:"user",
initialState,
reducers:{
},
extraReducers: (builder) => {
builder.addCase(login.pending, (state) => {
state.isLoading = true
})
builder.addCase(login.fulfilled, (state, action) => {
state.isLoading = false
state.isSuccess = true
state.userInfo = action.payload
})
builder.addCase(login.rejected, (state, action) => {
state.isLoading = false
state.isSuccess = true
state.userInfo = null
state.message = action.payload
})
}
})
export default userSlice.reducer
store:
import {configureStore, combineReducers} from '#reduxjs/toolkit'
import userReducer from './userSlice'
const rootReducer = combineReducers({
user: userReducer
})
export const store = configureStore({
reducer: rootReducer
})
export default store
login dispatch:
const onPressHandler = () =>{
dispatch(login({username, password}))
}
Related
Any idea why I am getting the error TypeError: undefined is not an object (evaluating '_useSelector.attendance') with redux.. Everything seems to be working fine but I just done understand why it keeps coming back to this.
Reducers.js
import { GET_ATTENDANCE, ADD_TO_ATTENDANCE_LIST } from "./actions";
const initialState = () => ({
attendance: [],
attendancebook: [],
});
function attendanceReducer(state = initialState, action) {
switch (action.type) {
case GET_ATTENDANCE:
return { ...state, attendance: action.payload };
case ADD_TO_ATTENDANCE_LIST:
return {
...state,
attendancebook: [...state.attendancebook, action.payload],
};
default:
return state;
}
}
export default attendanceReducer;
AttendanceScreen.js
function AttendanceScreen({ route }) {
const navigation = useNavigation();
const listing = route.params;
const dispatch = useDispatch();
const { attendance, attendancebook } = useSelector(
(state) => state.attendanceReducer
);
const getAttendance = () => {
try {
dispatch({
type: GET_ATTENDANCE,
payload: attendancelist,
});
} catch (error) {
console.log(error);
}
};
const fetchAttendance = () => dispatch(getAttendance());
const addToAttendanceList = (data) => dispatch(addAttendance(data));
useEffect(() => {
fetchAttendance();
}, []);
store.js
import attendanceReducer from "./reducers";
const persistConfig = {
key: "root",
storage: AsyncStorage,
whitelist: ["attendancebook"],
};
const rootReducer = combineReducers({
attendanceReducer: persistReducer(persistConfig, attendanceReducer),
});
export const store = createStore(rootReducer, applyMiddleware(thunk));
export const persistor = persistStore(store);
actions.js
export const GET_ATTENDANCE = "GET_ATTENDANCE";
export const ADD_TO_ATTENDANCE_LIST = "ADD_TO_ATTENDANCE_LIST";
export const addAttendance = (data) => (dispatch) => {
dispatch({
type: ADD_TO_ATTENDANCE_LIST,
payload: data,
});
};
Please any help will be appreciated.
I want to use reselect but I do not understand it correctly yet.
If I want to filter anything then I can do this:
const selectNumCompletedTodos = createSelector(
(state) => state.todos,
(todos) => todos.filter((todo) => todo.completed).length
)
But if I fetch, how does it look then? (I use useSelector and not mapToProps)
My Code:
Login:
imports
...
const Login = ({ navigation, route }) => {
const dispatch = useDispatch();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [passwordShown, setPasswordShown] = useState(true);
const handleGoBack = () => {
navigation.goBack();
};
const handleLogin = async () => {
const payload = {
email,
password
};
dispatch(request(payload));
};
return (
<View>
<TouchableOpacity onPress={handleLogin}>
<Text>click to fetch!</Text>
</TouchableOpacity>
</View>
)
authSaga.js
import { all, call, put, take, takeEvery, takeLatest } from 'redux-saga/effects';
import { request, authSuccess, authFailure } from '../slice/authSlice';
import authAPI from '../../api/auth';
import * as SecureStore from 'expo-secure-store';
function* auth({ payload }) {
const data = yield call(authAPI, payload);
yield put(authSuccess(data.user));
}
function* watcher() {
yield takeEvery(request.type, auth);
}
export default function* () {
yield all([watcher()]);
}
reducers:
import { combineReducers } from "redux";
import authReducer from './slice/authSlice';
const rootReducer = combineReducers({
user: authReducer,
});
export default rootReducer;
Slice:
import { createSlice } from '#reduxjs/toolkit';
const authSlice = createSlice({
name: 'user',
initialState: {
loading: false,
data: [],
error: null
},
reducers: {
request(state) {
state.loading = true;
},
authSuccess(state, action) {
state.loading = false;
state.data = action.payload;
},
authFailure(state, action) {
state.loading = false;
state.error = action.payload;
}
}
});
export const { request, authSuccess, authFailure } = authSlice.actions;
export default authSlice.reducer;
can anyone help me ?
................................................................................
So I dispatch my redux-saga action once from my react-native app and it makes two API calls. I'm trying to figure out why this is, and how to only have it send one.
App.js
const initFetch = async () => {
const userToken = await AsyncStorage.getItem("userToken");
dispatch(fetchLiked({ page: 0, search: "", userToken }));
};
useEffect(() => {
initFetch();
}, []);
configureStore.js
import { createStore, combineReducers, applyMiddleware } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import AsyncStorage from "#react-native-community/async-storage";
import likedReducer from "./reducers/liked";
import createSagaMiddleware from "redux-saga";
import rootSaga from "./sagas/rootSaga";
const rootReducer = combineReducers({
liked: likedReducer,
});
const persistConfig = {
key: "primary",
storage: AsyncStorage,
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
const sagaMiddleware = createSagaMiddleware();
export default () => {
let store = createStore(persistedReducer, applyMiddleware(sagaMiddleware));
sagaMiddleware.run(rootSaga);
let persistor = persistStore(store);
return { store, persistor };
};
rootSaga.js
import { take, call, all } from "redux-saga/effects";
import { watchFetchLikedSaga } from "./likedSaga";
export default function* rootSaga() {
yield all([watchFetchLikedSaga()]);
}
likedSaga.js
import { takeLatest, call, put } from "redux-saga/effects";
import Server from "../../utils/Server";
import { fetchLikedSuccess } from "./../actions/liked";
import { types } from "../actions/types";
function* asyncFetchLiked(data) {
console.log("sending async fetch");
const { page, search, userToken } = data.payload;
try {
const response = yield call(() =>
Server.get("/api/titles/getliked", {
headers: { "auth-token": userToken },
params: { page: page, search: search },
})
);
yield put(fetchLikedSuccess(response.data));
} catch (e) {
console.log(e);
}
}
export function* watchFetchLikedSaga() {
yield takeLatest(types.SEND_REQUEST, asyncFetchLiked);
}
export const fetchLiked = (data) => {
return {
type: types.SEND_REQUEST,
payload: data,
};
};
actions/liked.js
export const fetchLiked = (data) => {
console.log("fetchLiked");
return {
type: types.SEND_REQUEST,
payload: data,
};
};
export const fetchLikedSuccess = (data) => {
console.log("fetchLikedSuccess");
return {
type: types.SEND_REQUEST_SUCCESS,
payload: data,
};
};
export const fetchLikedFailure = (error) => {
return {
type: types.SEND_REQUEST_FAILURE,
payload: {},
error: error,
};
};
My console.log output looks like this. You can see the action is only being dispatched once, but it is sending two async requests and calling the reducer success action twice.
fetchLiked
sending async fetch
sending async fetch
fetchLikedSuccess
fetchLikedSuccess
so i am using Redux redux-thunk redux-persist and axios all together here is my setup:
**action.js**
import axios from 'axios';
import * as type from './constants';
export const handleSignup = userDetails => async (dispatch) => {
const {
email, password, username, version,
} = userDetails;
return axios
.post('/users/signup', {
email,
password,
username,
platform: version,
})
.then((res) => {
dispatch({
type: type.USER_SIGNUP_SUCCESS,
payload: res.data,
});
axios.defaults.headers.common.Authorization = `Bearer ${
res.data.access_token
}`;
return res;
});
};
**api.js**
import axios from 'axios';
import configureStore from '../store/configureStore';
const { store } = configureStore();
axios.defaults.baseURL = 'http://baseurl/api/v1';
axios.defaults.headers.common['Content-Type'] = 'application/json';
const accesToken = store.getState().authentication.token;
if (accesToken) {
axios.defaults.headers.common.Authorization = `Bearer ${accesToken}`;
}
axios.defaults.headers.common['Content-Type'] = 'application/json';
axios.interceptors.response.use(
async response => response,
error => Promise.reject(error),
);
**configureStore.js**
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
import { persistStore, persistCombineReducers } from 'redux-persist';
import rootReducer from '../reducers';
import storage from 'redux-persist/lib/storage';
const persistConfig = {
key: 'root',
storage,
blacklist: ['name1', 'name2', 'name3'],
};
const middlewares = [thunk];
const enhancer = composeWithDevTools(applyMiddleware(...middlewares));
const persistedReducer = persistCombineReducers(persistConfig, rootReducer);
export default () => {
const store = createStore(persistedReducer, undefined, enhancer);
const persistor = persistStore(store, null, () => {
store.getState();
});
return { store, persistor };
};
and i got this code inside my reducer for the signup success action
case type.USER_SIGNUP_SUCCESS:
return {
...state,
...action.payload.data.user,
email: action.payload.data.user.email,
username: action.payload.data.user.username,
token: action.payload.data.access_token,
user_id: action.payload.data.user.id,
};
and finally, i am calling handleSignUp on a submit button click:
onSignupClicked = () => {
this.setState({
error: false,
errorMessage: [],
loading: true,
});
const { platform } = Constants;
const version = Object.keys(platform)[0];
const {
user: { email, password, username },
} = this.state;
const { handleSignup, navigation } = this.props;
handleSignup({
email,
password,
username,
version,
})
.then(() => {
this.setState({ loading: true });
navigation.navigate(NAV_INTRO);
})
.catch((err) => {
console.log('ERROR : ',err)
});
};
sorry for a long code, so now my problem is that as soon as the user presses signup i am automatically getting ERROR : Network Error message. it doesn't wait for the request to get completed i guess, but the confusing part for me is this same code works on a previous version of the app with Expo 30.0.0, now its running on Expo 37.0.0. and i have double checked the API no problem with that, my question is is there something wrong with his code? is there a reason for it to return Network Error so fast?
i know this is bulky but any suggestion would be nice, Thanks.
in case its important here are my versions:
"react-redux": "5.0.7",
"redux": "4.0.0",
"redux-devtools-extension": "^2.13.8",
"redux-logger": "3.0.6",
"redux-mock-store": "1.5.3",
"redux-persist": "5.10.0",
"redux-thunk": "2.2.0",
I have problem to get token stored by Vuex in ~/plugins/axios.js. Hope your guys take a look for me please.
My Vuex: ~/store/index.js
export const state = () => ({
authUser: null,
token: null
})
export const mutations = {
SET_USER: function (state, user) {
state.authUser = user
},
SET_TOKEN: function (state, token) {
state.token = token
instance.defaults.headers = { Authorization: 'Bearer ' + token }
}
}
export const actions = {
async nuxtServerInit ({ commit }, { req }) {
...
},
async login ({ commit }, { username, password }) {
...
}
}
const store = () => new Vuex.Store({
state,
mutations,
actions,
modules: {
feed,
users,
notification,
messenger
}
})
export default store
const VuexStore = () => {
return store
}
export { VuexStore }
~/plugins/axios, which VuexStore.state is not data!
import axios from 'axios'
import {VuexStore} from '~/store'
var api = axios.create({
baseURL: 'http://localhost:8000/api/v1/'
})
console.log(VuexStore.state.token) // Null data
export default api
Console log is:
ƒ VuexStore() {
return store;
}
Not tested but you could use something like:
~/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = () => ({
authUser: null,
token: null
})
const mutations = {
SET_USER: function (state, user) {
state.authUser = user
},
SET_TOKEN: function (state, token) {
state.token = token
instance.defaults.headers = { Authorization: 'Bearer ' + token }
}
}
const getters = {
...
}
const actions = {
async nuxtServerInit ({ commit }, { req }) {
...
},
async login ({ commit }, { username, password }) {
...
}
}
export default new Vuex.Store({
state,
actions,
mutations,
getters,
modules: {
...
}
});
~/plugins/axios.js
import axios from 'axios'
import VuexStore from '~/store'
var api = axios.create({
baseURL: 'http://localhost:8000/api/v1/'
})
console.log(VuexStore.state.token)
export default api