Why my redux store is not getting firebase email property? React - javascript

I´m trying to do that when I login with firebase, i receive the user data in my Redux store.
When I alert() my email inside the onAuthStateChanged function i receive it, but when I try to alert my email from my other components I receive undefined
See, this is my onAuthState
firebase.auth().onAuthStateChanged(user => {
if (user) {
store.dispatch({
type: "USER_LOGIN",
payload: { user: user.providerData[0] }
});
} else {
store.dispatch({ type: "USER_LOGOUT" });
}
});
And this is my redux store
const reducer = (state, action) => {
switch (action.type) {
case "USER_LOGIN":
return { ...state, logged: true };
case "USER_LOGOUT":
return { ...state, logged: false };
default:
return state;
}
};
const initialState = {
logged: null,
user: []
};
Thanks!

Have you connect to redux from your other Component?
import React from 'react'
Import {connect} from 'react-redux'
...
class YourOtherComponent extends React.Component {
state = {
user: ''
}
componentDidMount(){
this.setState({user: this.props.user})
}
render(){
return(
<div>this.state.user</div>
)
}
}
mapStateToProps = state => ({
user: state.user
})
export default connect(mapStateToProps )(YourOtherComponent)

Related

Accessing state change from redux inside props, state successfully changes but props for that object is undefined

first questioner here!
I'm new to React and find it confusing to manage state with redux. From the redux-logger output, it seems that I am successfully changing the redux state regarding a user sign-in but I don't really know how to set it to props, and as such, I'm getting an undefined value for currentUser (which is the prop I want to manage across all my pages). I'm using both withRouter and Redux in an effort to pass user properties to app.js.
It starts with an API call to the backend to see if the user can login, if success then returns an object {isAdmin: "", uId: ""}.
import React from "react";
import { withRouter } from "react-router-dom";
import { setCurrentUser } from "../../redux/user/user-actions";
import { connect } from "react-redux";
// sign-in.jsx
class Login extends React.Component {
constructor(props) {
super(props);
}
onSubmitClick = async (e) => {
e.preventDefault();
fetch("/api/login", {
method: "post",
body: JSON.stringify({
email: "",
password: "",
}),
})
.then((res) => res.json())
.then((user) => {
if (user.error) {
this.setState({ error: user.error });
} else {
// Set the user in redux too:
this.props.dispatch(setCurrentUser(user));
// Redirect to main page after login
this.props.history.push({
pathname: "/",
search: "?uid=" + user.key + "?admin=" + user.admin,
state: { userId: user.key, isAdmin: user.admin },
});
}
});
};
render() {
return (...)
}
const mapStateToProps = ({ user }) => ({
currentUser: user.currentUser,
});
export default connect(mapStateToProps)(withRouter(Login));
The line with code: this.props.dispatch(setCurrentUser(user)); successfully changed the state but not the props value.
Here is the redux stuff:
// user-actions.js --------------------------------------------------------------------------------------
export const setCurrentUser = (user) => ({
type: "SET_CURRENT_USER",
payload: user,
});
// user-reducer.js --------------------------------------------------------------------------------------
// The initial state is basically a null user (ID)
const initialState = {
user: null,
};
/*
This is essentially a function that takes the current state
and action as an argument and returns a new state result.
i.e. (state, action) => newState
*/
const userReducer = (state = initialState, action) => {
// Conditional for the current action type
if (action.type.localeCompare("SET_CURRENT_USER") === 0) {
// Return a new state object
return {
// Which has the existing data but also..
...state,
// The new user object (just an ID at this point)
user: action.payload,
};
} else {
// Otherwise we return the state unchanged
// (usually when the reducer doesnt pick up the certain action)
return state;
}
};
export default userReducer;
// store.js --------------------------------------------------------------------------------------
import { createStore, applyMiddleware } from "redux";
/*
Useful for debugging redux --> logger
Is a logger middleware that console.logs the actions fired and change of state
*/
import logger from "redux-logger";
import rootReducer from "./root-reducer";
const middlewares = [logger];
const store = createStore(rootReducer, applyMiddleware(...middlewares));
export default store;
// root-reducer.js --------------------------------------------------------------------------------------
import { combineReducers } from "redux";
import userReducer from "./user/user-reducer";
export default combineReducers({
user: userReducer,
});
And finally, the App.js relevant code
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
...props,
u_id: null,
};
}
unsubscribeFromAuth = null;
componentDidMount() {
const { setCurrentUser } = this.props;[enter image description here][1]
const userState = this.props.location;
console.log(this.props);
// Make sure that state for a user isnt undefined
if (userState.state) {
this.unsubscribeFromAuth = true;
const user = userState.state.userId;
this.props.dispatch(setCurrentUser(user));
}
console.log(this.props);
}
componentWillUnmount() {
this.unsubscribeFromAuth = false;
}
render() {
return (...)
}
}
const mapStateToProps = (state) => ({
currentUser: state.currentUser,
});
//Access the state and dispatch function from our store
const mapDispatchToProps = (dispatch) => ({
setCurrentUser: (user) => dispatch(setCurrentUser(user)),
dispatch,
});
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(App));
Console output with redux-logger:
https://i.stack.imgur.com/r9JyV.png
As you can see, currentUser is undefined but all props in the location are there, I'm probably making some really dumb mistake when setting currentUser with the setCurrentUser action, both in the login and then again in the componentDidMount in the app.jsx
I'll add more detail upon request
Any help would be appreciated GREATLY! :)
You are saving the user in redux under user but you are trying to access it in the mapStateToPRops via currentUser:
const mapStateToProps = (state) => ({ currentUser: state.currentUser, });
Change it to const mapStateToProps = (state) => ({ currentUser: state.user, });
and it should work.
Also this:
const mapDispatchToProps = (dispatch) => ({
setCurrentUser: (user) => dispatch(setCurrentUser(user)),
dispatch,
});
is equivalente to:
const mapDispatchToProps = ({
setCurrentUser
});
https://react-redux.js.org/using-react-redux/connect-mapdispatch#defining-mapdispatchtoprops-as-an-object

Redux Form action undefined

I am trying to do authorization.
I get the data from reduxForm, and it is visible, but for some reason the data does not immediately get into the function, but goes to action, and I get an undefined value.
Registration is carried out on the same principle, but there are no errors.
Where could my mistake be?
REDUX
const NewUserEror = "NewUserEror";
const RegSucces = "RegSucces";
const RegStart = "RegStart";
const RegEnd = "RegEnd";
let initialState = {
error: null,
loading: false
};
const registrationReducer = (state = initialState, action) => {
switch (action.type) {
case RegSucces:
return {
...state,
error: false
};
case NewUserEror:
return {
...state,
error: action.payload
};
case RegStart:
return {
...state,
loading: true
};
case RegEnd:
return {
...state,
loading: false
};
default:
return state;
}
};
export const LogInUser = data => async (
dispatch,
getState,
{ getFirebase }
) => {
const firebase = getFirebase();
dispatch({ type: RegStart });
try {
await firebase.auth().signInWithEmailAndPassword(data.email, data.password);
dispatch({ type: RegSucces });
} catch (err) {
dispatch({ type: NewUserEror, payload: err.message });
}
dispatch({ type: RegEnd });
};
CONTAINER
import React from "react";
import { connect } from "react-redux";
import Login from "./login";
import LogInUser from "./../../../redux/registrationReducer"
class AuthBox extends React.Component{
Userlogin=(formdata)=>{
this.props.LogInUser(formdata)
}
render(){
return<Login {...this.props} Userlogin={this.Userlogin}></Login>
}
}
let mapStateToProps=(state)=>{
return{
loading:state.Regis.loading,
error:state.Regis.error
}
}
export default connect(mapStateToProps,{LogInUser})(AuthBox);
COMPONENT
const Login = props => {
let onSubmit = formData => {
props.Userlogin(formData);
};
return (
<div className={classes.formbox}>
<div className={classes.form}>
<h5 className={classes.formtitle}>Вход</h5>
<LoginForm onSubmit={onSubmit}></LoginForm>
</div>
</div>
);
};
export default Login;
Error
Action undefined
p.s sorry for my english
NON DEFAULT EXPORT MUST BE IN {}
import React from "react";
import { connect } from "react-redux";
import Login from "./login";
////// here
import {LogInUser} from "./../../../redux/registrationReducer"
////
class AuthBox extends React.Component{
Userlogin=(formdata)=>{
this.props.LogInUser(formdata)
}
render(){
return<Login {...this.props} Userlogin={this.Userlogin}></Login>
}
}
let mapStateToProps=(state)=>{
return{
loading:state.Regis.loading,
error:state.Regis.error
}
}
export default connect(mapStateToProps,{LogInUser})(AuthBox);

React Component fails to re-render after update from Redux Store

Can anyone help me figure out why my Component is not updating after dispatch?
function mapStateToProps(state) {
const { isAuthenticated } = state
return { isAuthenticated }
}
class LoginForm extends Component {
handleSubmit(event) {
event.preventDefault();
const { dispatch } = this.props
const credentials = this.state
dispatch(attemptLogIn(credentials));
}
// Dispatch works properly when API validates Login:
// Redux Log:
// nextState:{ authReducer: {isAuthenticated: true}}
render() {
const { isAuthenticated } = this.props;
return (
<div>
{ isAuthenticated && <div> Authenticated: True </div> }
// Does not render even after dispatch
<form onSubmit={this.handleSubmit}>
{... Form Stuff ...}
</form>
</div>
)
}
export default withRouter(connect(mapStateToProps)(LoginForm))
Just simple conditional render from Redux store, I am expecting the extra div to show up to inform the user that he has authenticated, but It does not render.
This type of example of conditional rendering was used in the AsyncApp example during the Redux Async Tutorial, so I'm not sure why it doesn't work. My actions are dispatched, and reducers successfully update the state, passing it down to the connected component. Here are my reducers:
const initialState = { isAuthenticated: false}
const authReducer = (state = initialState, action) => {
switch(action.type){
case ('USER_AUTHENTICATED'): {
return Object.assign({}, state, {
isAuthenticated: true,
userPermissions: action.userInfo.userPermissions,
instanceType: action.userInfo.instanceType
}
)
}
case ('INVALID_CREDENTIALS'): {
return Object.assign({}, state, {
isAuthenticated:false
}
)
}
case ('LOG_OUT'): {
return initialState
}
default:
return state
}
}
const rootReducer = combineReducers({
authReducer,
routerReducer
})
export default rootReducer
Does anyone know why my Component does not re-render?
Change your mapStateToProps function to this.
function mapStateToProps(state) {
const { isAuthenticated } = state.authReducer;
return { isAuthenticated };
}

Redux - Why is loginStatus undefined when component first starts rendering

I'm learning Redux and have come across an issue that I have not encountered before when using React without redux. I'm trying to display a piece of my state inside one of my components name loginStatus. The reducer I have setup this state with has an initial state but whenever I try and launch the application I get the console error:
Cannot read property 'loginStatus' of undefined
Here is my code:
Component
import React, {Component} from 'react';
import {connect} from 'react-redux';
import { bindActionCreators } from 'redux';
import * as authActions from './userAuthActions';
class App extends Component {
constructor(props) {
super(props);
}
render() {
if(typeof(this.props.userAuthReducer) !== 'undefined') {
test = this.props.userAuthReducer.loginStatus;
console.log(test)
} else {
console.log("it's undefined")
}
return (
<div className={"popup-logins " + this.props.userAuthReducer.loginStatus}>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
userAuthReducer:state.userAuthReducer
};
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators(authActions,dispatch);
};
export default connect(mapStateToProps,mapDispatchToProps)(App);
userAuthActions.js
export const loginUser = () => {
return {
type:'loginUser',
loggedIn:true
}
}
export const toggleRegLog = () => {
return {
type:'toggleRegLog'
}
}
userAuthReducer
let initialState = {
loginStatus: "not-logged-in"
, toggleRegLog: 'login'
};
const userAuthReducer = (state = initialState, action) => {
switch (action.type) {
case 'loginUser':
let newState;
if (action.loggedIn) {
Object.assign({}, state, {
loginStatus: "logged-in"
})
}
else {
Object.assign({}, state, {
loginStatus: "not-logged-in"
})
}
return newState;
break;
default:
return state;
}
}
export default userAuthReducer;
combine reducers
import {combineReducers} from 'redux';
import userAuthReducer from './userAuthReducer';
function lastAction(state = null, action) {
return action;
}
export default combineReducers({
lastAction,userAuthReducer
});
What's strange is that I initially get a console.log of it's undefined" when I first start up the app and then immediately after I get the value "not-logged-in". I need to use this to hide/ show certain parts of my app if the user is logged in.
Normally if I use React without Redux I use this method all the time without any issues but can't understand what I might have done wrong here?
Thanks
You're not really assigning a value to newState in your reducer, so essentially you're returning undefined, which of course doesn't have a loginStatus property. Changing your reducer so to something like this will probably solve the problem:
let initialState = {
loginStatus: "not-logged-in"
, toggleRegLog: 'login'
};
const userAuthReducer = (state = initialState, action) => {
switch (action.type) {
case 'loginUser':
let newState;
if (action.loggedIn) {
newState = Object.assign({}, state, {
loginStatus: "logged-in"
})
}
else {
newState = Object.assign({}, state, {
loginStatus: "not-logged-in"
})
}
return newState;
break;
default:
return state;
}
}
export default userAuthReducer;
Object.assign returns a new object, applies the data from state and the last argument containing the loginStatus property and passes that to the newState variable, which gets returned at the end of the switch case.
Edit
This edit below makes it easier to reason about the logic in the reducer:
let initialState = {
loginStatus: "not-logged-in"
, toggleRegLog: 'login'
};
const userAuthReducer = (state = initialState, action) => {
switch (action.type) {
case 'loginUser':
if (action.loggedIn) {
return Object.assign(state, { loginStatus: "logged-in" })
}
return Object.assign(state, { loginStatus: "not-logged-in" })
default:
return state;
}
}
export default userAuthReducer;

mapStateToProps returning undefined state from reducer

I am getting this error:
I have this reducer for async:
const initUserState = {
fetching: false,
fetched: false,
users: [],
error: null
};
const userReducer = (state = initUserState, action) => {
switch(action.type){
case "FETCH_USER":
state = {
...state,
users : action.payload
};
break;
case "FETCH_USER_START":
state = {
...state,
fetching: true
};
break;
case "FETCH_USER_SUCCESS":
state = {
...state,
fetched: true,
users: action.payload
};
break;
case "FETCH_USER_ERROR":
state = {
...state,
fetched: false,
error: action.payload
};
break;
default:
break;
}
return state;
};
export default userReducer;
And my container is:
import React from 'react';
import { Blog } from '../components/Blog';
import { connect } from 'react-redux';
//import { act_fetchAllUser } from '../actions/userActions';
import axios from 'axios';
class App extends React.Component {
componentWillMount(){
this.props.fetchAllUser();
}
render(){
console.log("Prop: " , this.props.user);
return(
<div>
<h1>My Blog Posts</h1>
<Blog/>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
user: state.userReducer
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchAllUser: () => {
dispatch((dispatch) => {
dispatch({ type: "FETCH_USER_START" })
axios.get('http://infosys.esy.es/test/get_allBlog.php')
.then((response) => {
dispatch({
type: "FETCH_USER_SUCCESS",
payload: response.data
});
})
.catch((err) => {
dispatch({
type: "FETCH_USER_ERROR",
payload: err
});
})
});
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
Im new to redux and I am into async now...
my application should load the users on page load but why my user state is returning undefined state? in the render method, i am logging the user props that contains the returned state from userReducer(mapStateToProps) but i am getting undefined. But when I getState() in store and log it, I am getting the expected result but it is not the ideal place to get the state right?... What i am doing wrong?
My store is:
import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';
import userReducer from './reducers/userReducer';
import thunk from 'redux-thunk';
const store = createStore(userReducer,applyMiddleware(thunk, logger()));
//store.subscribe(() => console.log('State: ',store.getState()));
export default store;
And my index is:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './container/App';
import { Provider } from 'react-redux';
import store from './store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider> , document.getElementById('root'));
Also, on my default case in userReducer, what should I code there.. should I just break; or do I need also to return state it? Thank you
You should have;
const mapStateToProps = (state) => {
return {
user: state.users
};
};
mapStateToProps passes state (global store) as a props to the component.
Global store
const initUserState = {
fetching: false,
fetched: false,
users: [],
error: null
};
inside component listening to user state
const mapStateToProps = (state) => {
return {
user: state.users
};
};

Categories

Resources