Reputation: 741
I'm using Redux DevTools Chrome Extension and can see in it that auth.isSignedIn in the Redux store is populated properly through the Register component. But then when it rerenders when I redirect to home, I can't access this.state.auth.isSignedIn in App.js to properly route the user to the normal home page component. What am I doing wrong here? This is my first independent React project after doing training (but I've been a developer for a long time).
App.js App Component
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import { connect } from 'react-redux';
import Header from './Header';
import history from '../history';
import Login from './Login/Login';
import Register from './Login/Register';
class App extends React.Component {
state = { isSignedIn: null };
render(){
console.log('getting isSigned in');
if(this.state.auth && this.state.auth.isSignedIn){
console.log('it has VALUE');
console.log(this.state.auth.isSignedIn);
}else{
console.log('no isSignedIn');
}
}
}
const mapStateToProps = (state) => {
return { isSignedIn: state.auth.isSignedIn };
};
export default connect(mapStateToProps)(App);
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose } from 'redux';
import reduxThunk from 'redux-thunk';
import App from './components/App';
import reducers from './reducers';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducers,
composeEnhancers(applyMiddleware(reduxThunk))
);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.querySelector('#root')
);
Register.js Register Component
import React from 'react';
import { register } from '../../actions';
import { connect } from 'react-redux';
import LoginForm from './LoginForm';
class Register extends React.Component {
onSubmit = (formValues) => {
this.props.register(formValues);
}
render(){
return(
<div >
<LoginForm formHeading="Register Now" onSubmit={this.onSubmit} />
</div>
);
}
}
const mapStateToProps = (state) => {
return { isSignedIn: state.auth.isSignedIn };
};
export default connect(mapStateToProps, { register })(Register);
actions/index.js Action Creator
import listItems from '../apis/listItems';
import user from '../apis/user';
import history from '../history';
import { SIGN_IN, SIGN_OUT, REGISTER, CREATE_LIST_ITEM, EDIT_LIST_ITEM, DELETE_LIST_ITEM, FETCH_LIST_ITEM, FETCH_LIST_ITEMS, MARK_COMPLETED_LIST_ITEM } from './types';
export const signIn = formValues => async (dispatch, getState) => {
let data = new FormData();
data.append('request', 'login');
data.append('email', formValues.email);
data.append('password', formValues.password);
const response = await listItems.post('/user', data);
dispatch({ type: SIGN_IN, payload: response.data });
history.push('/');
return {
type: SIGN_IN,
payload: response.data
};
};
export const register = (formValues) => async (dispatch, getState) => {
let data = new FormData();
data.append('request', 'register');
data.append('email', formValues.email);
data.append('password', formValues.password);
const response = await user.post('/user', data);
dispatch({ type: REGISTER, payload: response.data });
history.push('/');
return {
type: REGISTER,
payload: response.data
};
};
export const signOut = () => {
return {
type: SIGN_OUT
};
};
export const createListItem = formValues => async (dispatch, getState) => {
let data = new FormData();
data.append('listItem', formValues.list_item);
data.append('completionLabel', formValues.completion_label);
const response = await listItems.post('/listItemsMaintenance', data);
dispatch({ type: CREATE_LIST_ITEM, payload: response.data });
history.push('/');
};
export const fetchListItems = () => async dispatch => {
const response = await listItems.get('/listItemsMaintenance');
dispatch({ type: FETCH_LIST_ITEMS, payload: response.data });
};
export const fetchListItem = (id) => async dispatch => {
let data = new FormData();
data.append('list_item_id', id);
const response = await listItems.get(`/listItemsMaintenance?list_item_id=${id}`);
dispatch({ type: FETCH_LIST_ITEM, payload: response.data});
};
export const editListItem = (list_item_id, formValues) => async dispatch => {
let data = new FormData();
data.append('request', 'edit');
data.append('list_item_id', list_item_id);
data.append('listItem', formValues.list_item);
data.append('completionLabel', formValues.completion_label);
const response = await listItems.post(`/listItemsMaintenance`, data);
dispatch({ type: EDIT_LIST_ITEM, payload: {...formValues, list_item_id } });
history.push('/');
};
export const markListItemCompleted = (list_item_id) => async dispatch => {
let data = new FormData();
data.append('request', 'markCompleted');
data.append('list_item_id', list_item_id);
const response = await listItems.post('/listItemsMaintenance', data);
// not sure what the payload actually needs to be
dispatch({ type: MARK_COMPLETED_LIST_ITEM, payload: {...response.data, list_item_id } });
history.push('/');
};
export const deleteListItem = (list_item_id) => async dispatch => {
let data = new FormData();
data.append('request', 'delete');
data.append('list_item_id', list_item_id);
await listItems.post(`/listItemsMaintenance`, data);
dispatch({ type: DELETE_LIST_ITEM, payload: list_item_id });
history.push('/');
};
reducers/authReducer.js Reducer
import { SIGN_IN, SIGN_OUT, REGISTER } from '../actions/types';
const INITIAL_STATE = {
isSignedIn: null,
userId: null
};
export default (state = INITIAL_STATE, action) => {
switch (action.type){
case REGISTER:
return {...state, isSignedIn: true, userId: action.payload };
case SIGN_IN:
return {...state, isSignedIn: true, userId: action.payload };
case SIGN_OUT:
return {...state, isSignedIn: false, userId: null};
default:
return state;
}
};
Upvotes: 0
Views: 612
Reputation: 51
You're mapping your redux state to your props with this function:
const mapStateToProps = (state) => {
// Suggestion, map the whole auth object:
// return { auth: state.auth };
return { isSignedIn: state.auth.isSignedIn };
};
Here you say you want the property isSignedIn to be populated with the redux state.auth.isSignedIn.
As the name of the function describes: you're mapping your redux state to your PROPS.
In your code you used the state again to try to get the previously mapped value.
class App extends React.Component {
// state = { isSignedIn: null }; This could be removed
// For simplicity and readability's sake I suggest to
// destructure your props into seperate variables like this
const { isSignedIn } = this.props; // <--- Make sure to use PROPS and not STATE
// FYI you mapped your redux state to an object with property isSignedIn,
// and only mapped that variable, as stated before
// You did not map the whole auth object so you can't reach that here
render(){
console.log('getting isSigned in');
// if(this.state.auth && this.state.auth.isSignedIn){ <--- Your code
// I liked your comparison, above this line, but you didn't map the
// whole object so you can't check if auth is null here
if(isSignedIn){
console.log('it has VALUE');
console.log(isSignedIn);
}else{
console.log('no isSignedIn');
}
}
}
Upvotes: 1
Reputation: 4147
You redux state gets added to this.props
when you pass in the mapStateToProps
argument to the connect
function.
In your case you should be able to access isSignedIn
by using this.props.isSignedIn
Upvotes: 0
Reputation: 2053
To get something from store you should use hook names useSelector from react-redux
import { useSelector } from 'react-redux'
// inside component
const state = useSelector( state => state ) // return whole store
const isSignedIn = useSelector( state => state.auth.isSignedIn ) // return only isSignedIn value
Upvotes: 0