Reputation: 2089
I have created an authentification system in react with redux and axios but I can`t figure out how to render the data in my components.
This is my actions/auth.js:
import axios from 'axios';
import {
SIGNUP_SUCCESS,
SIGNUP_FAIL,
LOGIN_SUCCESS,
LOGIN_FAIL,
ACTIVATION_SUCCESS,
ACTIVATION_FAIL,
RESET_PASSWORD_SUCCESS,
RESET_PASSWORD_FAIL,
RESET_PASSWORD_CONFIRM_SUCCESS,
RESET_PASSWORD_CONFIRM_FAIL,
LOGOUT,
USER_LOADED_SUCCESS,
USER_LOADED_FAIL,
AUTHENTICATED_FAIL,
AUTHENTICATED_SUCCESS
} from './types';
export const checkAuthenticated = () => async dispatch => {
if (typeof window == 'undefined') {
dispatch({
type: AUTHENTICATED_FAIL
});
}
if (localStorage.getItem('access')) {
const config = {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
};
const body = JSON.stringify({ token: localStorage.getItem('access') });
try {
const res = await axios.post(`${process.env.REACT_APP_API_URL}/auth/jwt/verify/`, body, config);
if (res.data.code !== 'token_not_valid') {
dispatch({
type: AUTHENTICATED_SUCCESS
});
} else {
dispatch({
type: AUTHENTICATED_FAIL
});
}
} catch (err) {
dispatch({
type: AUTHENTICATED_FAIL
});
}
} else {
dispatch({
type: AUTHENTICATED_FAIL
});
}
};
export const load_user = () => async dispatch => {
if (localStorage.getItem('access')) {
const config = {
headers: {
'Content-Type': 'application/json',
'Authorization': `JWT ${localStorage.getItem('access')}`,
'Accept': 'application/json'
}
};
try {
const res = await axios.get(`${process.env.REACT_APP_API_URL}/auth/users/me/`, config);
dispatch({
type: USER_LOADED_SUCCESS,
payload: res.data
});
} catch (err) {
dispatch({
type: USER_LOADED_FAIL
});
}
} else {
dispatch({
type: USER_LOADED_FAIL
});
}
};
export const login = (email, password) => async dispatch => {
const config = {
headers: {
'Content-Type': 'application/json'
}
};
const body = JSON.stringify({ email, password });
try {
const res = await axios.post(`${process.env.REACT_APP_API_URL}/auth/jwt/create/`, body, config);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
dispatch(load_user());
} catch (err) {
dispatch({
type: LOGIN_FAIL
});
}
};
export const logout = () => dispatch => {
dispatch({ type: LOGOUT });
};
This is my reducers/auth.js:
import {
SIGNUP_SUCCESS,
SIGNUP_FAIL,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT,
AUTHENTICATED_FAIL,
AUTHENTICATED_SUCCESS,
USER_LOADED_SUCCESS,
USER_LOADED_FAIL
} from '../actions/types';
const initialState = {
access: localStorage.getItem('access'),
refresh: localStorage.getItem('refresh'),
isAuthenticated: null,
user: null
};
export default function(state = initialState, action) {
const { type, payload } = action;
switch(type) {
case AUTHENTICATED_SUCCESS:
return {
...state,
isAuthenticated: true
}
case LOGIN_SUCCESS:
localStorage.setItem('access', payload.access);
return {
...state,
isAuthenticated: true,
access: payload.access,
refresh: payload.refresh
}
case USER_LOADED_SUCCESS:
return {
...state,
user: payload
}
case AUTHENTICATED_FAIL:
return {
...state,
isAuthenticated: false
}
case USER_LOADED_FAIL:
return {
...state,
user: null
}
case LOGIN_FAIL:
case LOGOUT:
localStorage.removeItem('access');
localStorage.removeItem('refresh');
return{
...state,
access: null,
refresh: null,
isAuthenticated: false,
user: null
}
default:
return state
}
}
If I log in and use the redux Devtool I can see this state:
{
auth: {
access: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjAzNDgzODY1LCJqdGkiOiJhYTAzYzIzNTUwN2M0YTkxYjA2NjNmNDc0ZTU2MjIxMSIsInVzZXJfaWQiOjF9.Jyld4U7i6EqmsNoi0_qT9O9Kcu1TiEuyLLYCWWaoBrU',
refresh: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYwMzU2OTk2NSwianRpIjoiOWIzMWIyN2M1ODkyNDRiZDk3Y2EwMDI1NTY2Mzk3ZWMiLCJ1c2VyX2lkIjoxfQ.UgH_753OoWD3NXiwPwa1645_vIHUl-FwyvQMJWMgHtk',
isAuthenticated: true,
user: {
name: 'Jonas Levin',
id: 1,
email: '[email protected]'
}
}
}
But I can`t figure out how to display the data, for example user.name.
I already tried to use mapStateToProps in one of my components but I get the error: "TypeError: Cannot read property 'name' of undefined"
const mapStateToProps = state => ({
userName: state.user.name,
userEmail: state.user.email
});
Edit
This is the response data that I get. But as you can see there is another API call which is still from the login page where I was on before I got redirected to '/' and that light red /me call has an error message in it because when your on the login page you don`t have an access token.
How can I access this response data in my Components to render the Name?
Store.js:
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const initialState = {};
const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;
Upvotes: 1
Views: 238
Reputation: 2089
I managed to access the username in my layout.js file by adding the state to the props:
const mapStateToProps = (state, ownProps) => {
return {
isAuthenticated: state.auth.isAuthenticated,
user: state.auth.user,
props: ownProps
}
};
I used ownProps to be able to also use props.children in the layout container. Than I gave tham as parameters to the layout container and was able to access the username with user.name. I´m not entirely sure why it worked now and not before when I already tried to use mapStateToProps.
Upvotes: 1
Reputation: 1984
If you use a functional component, you could use useSelector
hook.
const user = useSelector(state => state.auth.user)
Upvotes: 0
Reputation: 1764
this is how you should do it access auth reducer then th user
const mapStateToProps = state => ({
userName: state.auth.user.name,
userEmail: state.auth.user.email
});
this is how redux works , let's say this is your store
import {cartReducer} from './reducers/CartReducer'
import { authReducer } from './reducers/AuthReducer'
import { ordersReducer } from './reducers/OrdersReducer'
import { errorsReducer } from './reducers/ErrorsReducer'
const initialState={
products:{
items:[],
filterdProducts:[]
},
cart:{
items:[],
},
orders:{
items:[],
canOrder:true,
},
auth: {
access: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjAzNDgzODY1LCJqdGkiOiJhYTAzYzIzNTUwN2M0YTkxYjA2NjNmNDc0ZTU2MjIxMSIsInVzZXJfaWQiOjF9.Jyld4U7i6EqmsNoi0_qT9O9Kcu1TiEuyLLYCWWaoBrU',
refresh: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYwMzU2OTk2NSwianRpIjoiOWIzMWIyN2M1ODkyNDRiZDk3Y2EwMDI1NTY2Mzk3ZWMiLCJ1c2VyX2lkIjoxfQ.UgH_753OoWD3NXiwPwa1645_vIHUl-FwyvQMJWMgHtk',
isAuthenticated: true,
user: {
name: 'Jonas Levin',
id: 1,
email: '[email protected]'
}
},
error:{
msg:null,
status:null,
id:null
}
}
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(combineReducers({
products: productsReducer,
cart : cartReducer ,
orders : ordersReducer ,
auth : authReducer,
error : errorsReducer ,
}),
initialState,
composeEnhancer(applyMiddleware(thunk))
)
export default store
if you want to access user from any other component you'mm need to access auth reducer first , same for items you can either access products.items or cart .items and so on
Upvotes: 0