Cannot read property 'isAuthenticated' of undefined - reactjs

TypeError: Cannot read property 'isAuthenticated' of undefined
Function.mapStateToProps [as mapToProps]
E:/smnd/client/src/components/auth/Login.js:69
function mapStateToProps (state){
return{
isAuthenticated: state.auth.isAuthenticated
}
}
this is the code of Login.js
import React, {Fragment, useState } from 'react';
import {Link, Redirect} from 'react-router-dom';
import {connect} from 'react-redux';
import PropTypes from 'prop-types';
import {login} from '../../actions/auth';
// import {isAuthenticated} from '../../reducers/auth';
const Login = ({login, isAuthenticated}) => {
const [formData, setFormData] = useState({
email: '',
password: ''
});
const { email, password} = formData;
const onChange = e => setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = async e => {
e.preventDefault();
login(email,password);
};
// redirected if logged in
if (isAuthenticated) {
return <Redirect to='/dashboard' />;
}
return (
<Fragment>
<h1 className="large text-primary">Sign In</h1>
<p className="lead"><i className="fas fa-user"></i> Sign Into Your Account</p>
<form className="form" onSubmit={e => onSubmit(e)}>
<div className="form-group">
<input type="email" placeholder="Email Address" name="email" value={email} onChange={ e => onChange(e)} />
</div>
<div className="form-group">
<input
type="password"
placeholder="Password"
name="password"
value={password}
onChange={ e => onChange(e)}
/>
</div>
<input type="submit" className="btn btn-primary" value="Login" />
</form>
<p className="my-1">
Don't have an account? <Link to="/register">Sign Up</Link>
</p>
</Fragment>
);
};
Login.propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
}
// const mapStateToProps = state => ({
// isAuthenticated: state.auth.isAuthenticated
// });
function mapStateToProps (state){
return{
isAuthenticated: state.auth.isAuthenticated
}
}
export default connect(mapStateToProps, {login}) (Login);

Because you don't set the initial state of auth in the redux store. So you need to add optional chaining like this:
isAuthenticated: state.auth?.isAuthenticated

Make sure that in the login reducer of redux store , you have provided the "isAuthenticated" as initialState like the below..
const initialState = {
isAuthenticated: false,
};
function loginReducer(state = initialState, action){
....
}
Also make sure that you have included the loginReducer in the "combineReducers" function , if you are using multiple reducers for your redux store

Related

my form won't refresh back to initial state or navigate to the feeds page after success full registration i'm i wrong using async?

my form won't refresh back to initial state or navigate to the feeds page after success full registration and now react is telling me Async await is only available in es8 please can i go about this i want the form to provide some kind of feedback after registration like to n avigate to the homepage and clear all field but it's not working
import { Link, useNavigate } from 'react-router-dom'
import { toast } from 'react-toastify'
import {
getAuth,
createUserWithEmailAndPassword,
updateProfile,
} from 'firebase/auth'
import { setDoc, doc, serverTimestamp } from 'firebase/firestore'
import { db } from '../firebase.config'
import OAuth from '../components/OAuth'
function SignUp() {
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
})
const { name, email, password } = formData
const navigate = useNavigate()
const onChange = (e) => {
setFormData((prevState) => ({
...prevState,
[e.target.id]: e.target.value,
}))
}
const onSubmit = async (e) => {
e.preventDefault()
try {
const auth = getAuth()
const userCredential = await createUserWithEmailAndPassword(
auth,
email,
password
)
const user = userCredential.user
updateProfile(auth.currentUser, {
displayName: name,
})
const formDataCopy = { ...formData }
delete formDataCopy.password
formDataCopy.timestamp = serverTimestamp()
await setDoc(doc(db, 'users', user.uid), formDataCopy)
navigate('/')
} catch (error) {
toast.error('Something went wrong with registration')
}
}
return (
<>
<div className='pageContainer'>
<header>
<p className='pageHeader'>Welcome Back!</p>
</header>
<form onSubmit={onSubmit}>
<input
type='text'
className='nameInput'
placeholder='Name'
id='name'
value={name}
onChange={onChange}
/>
<input
type='email'
className='emailInput'
placeholder='Email'
id='email'
value={email}
onChange={onChange}
/>
<div className='passwordInputDiv'>
<input
type='password'
className='passwordInput'
placeholder='Password'
id='password'
value={password}
onChange={onChange}
/>
</div>
<Link to='/forgot-password' className='forgotPasswordLink'>
Forgot Password
</Link>
<div className='signUpBar'>
<p className='signUpText'>Sign Up</p>
<button className='signUpButton'>
Sign Up
</button>
</div>
</form>
<OAuth />
<Link to='/sign-in' className='registerLink'>
Sign In Instead
</Link>
</div>
</>
)
}
export default SignUp

Login is not a function after logging out then trying to log back in

I am building a react project where I want to implement a log-in/ log out screen.
I am able to succesfully log in but once I log out, I cannot log back in with the error "TypeError
Login is not a function" being displayed. It seems to be coming from LogInForm.js, from the Login(details); line. I cannot spot my mistake here so I would greatly appreciate any feedback. Cheers.
LogInForm.js
import React, { useState } from "react";
function LogInForm({ Login, error }) {
const [details, setDetails] = useState({ email: "", password: "" });
const submitHandler = (e) => {
e.preventDefault();
Login(details);
};
return (
<form onSubmit={submitHandler}>
<div className="form-inner">
<h2>Login</h2>
{/* ERROR!*/}
<div className="form-group">
<label htmlFor="email">Email:</label>
<input
type="email"
name="email"
id="email"
onChange={(e) => setDetails({ ...details, email: e.target.value })}
value={details.email}
/>
</div>
<div className="form-group">
<label htmlFor="password">Password:</label>
<input
type="password"
name="password"
id="password"
onChange={(e) =>
setDetails({ ...details, password: e.target.value })
}
value={details.password}
/>
</div>
<input type="submit" value="Log In" />
</div>
</form>
);
}
export default LogInForm;
LogIn.js
import React, { useState } from "react";
import App from "./App";
import LogInForm from "./LogInForm";
function LogIn() {
const adminUser = {
email: "admin#admin.com",
password: "test123"
};
const [user, setUser] = useState({ name: "", email: "" });
const [error, setError] = useState("");
const Login = (details) => {
if (
details.email == adminUser.email &&
details.password == adminUser.password
) {
console.log("Logged in!");
setUser({ email: details.email, password: details.password });
} else {
console.log("details dont match");
}
};
const Logout = () => {
console.log("Logout");
};
return (
<div className="Display">
{user.email != "" ? (
<App email={user.email} password={user.password} />
) : (
<LogInForm Login={Login} error={error} />
)}
</div>
);
}
export default LogIn;
index.js
import React from "react";
import ReactDOM from "react-dom";
import LogIn from "./LogIn";
ReactDOM.render(<LogIn />, document.getElementById("root"));
App.js
import React from "react";
import LogIn from "./LogIn";
import LogInForm from "./LogInForm";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
email: this.props.email,
password: this.props.password,
};
this.logOut = this.logOut.bind(this);
}
logOut() {
console.log("Logged out");
this.setState({ email: "", password: "" });
}
componentDidMount() {
console.log("Email:" + this.state.email);
console.log("Password:" + this.state.password);
}
render() {
if (this.state.email == "") {
return <LogInForm />;
} else {
{
console.log(this.state);
}
return (
<div>Hello</div>,
<button onClick={this.logOut}>Log Out</button>
);
}
}
}
export default App;
The issue is haven't passed Login function in App file. This could be done in a more simple way, like this.
function LogInForm({ handleLogin, user, setUser }) {
return (
<form onSubmit={handleLogin}>
<div className="form-inner">
<h2>Login</h2>
{/* ERROR!*/}
<div className="form-group">
<label htmlFor="email">Email:</label>
<input
type="email"
name="email"
id="email"
onChange={(e) => setUser({ ...user, email: e.target.value })}
value={user.email}
/>
</div>
<div className="form-group">
<label htmlFor="password">Password:</label>
<input
type="password"
name="password"
id="password"
onChange={(e) => setUser({ ...user, password: e.target.value })}
value={user.password}
/>
</div>
<input type="submit" value="Log In" />
</div>
</form>
);
}
const adminUser = {
email: "admin#admin.com",
password: "test123"
};
export default function App() {
const [user, setUser] = useState({ name: "", email: "" });
const [isAuthenticated, setIsAuthenticated] = useState(false);
const handleLogin = () => {
if (
user.email === adminUser.email &&
user.password === adminUser.password
) {
console.log("Logged in!");
setIsAuthenticated(true);
} else {
console.log("details dont match");
}
};
const handleLogout = () => {
setIsAuthenticated(false);
console.log("Logout");
};
return (
<div className="Display">
{isAuthenticated ? (
<button onClick={handleLogout}>logout</button>
) : (
<LogInForm
handleLogin={handleLogin}
user={user}
setUser={setUser}
/>
)}
</div>
);
}

Open a new component when the register button is clicked

Open as a new page and the user goes inside the page when the button is clicked. How can I do it in react functional component? I want to navigate from Register to another MyProfile component when button is clicked. The code for Register component is as below:
import React, { useState } from 'react'
import './Register.css'
import axios from 'axios'
import { useHistory } from 'react-router-dom'
function Register() {
const history = useHistory();
const [data, setData] = useState({
name: "",
email: "",
password: "",
confirmpassword: "",
});
const register = (e) => {
e.preventDefault();
history.push("/myprofile")
}
const InputEvent = (event) => {
const { name, value } = event.target;
setData((preVal) => {
return {
...preVal,
[name]: value,
};
});
};
const formSubmit = (e) => {
e.preventDefault();
};
return (
<div className="signup__container">
<div className="signup__containerInfo">
<h1 className="h1__swari">swari</h1>
<hr />
</div>
<form4 onSubmit={formSubmit}>
<h5 className="h5__form"> Name</h5>
<input type="text" placeholder="Full Name" name="name" value={data.name} onChange={InputEvent} />
<h5 className="h5__form"> Email-Address </h5>
<input type="Email" placeholder="Email" name="email" value={data.email} onChange={InputEvent} />
<h5 className="h5__form"> Password </h5>
<input type="Password" placeholder="Password" name="password" value={data.password} onChange={InputEvent} />
<h5 className="h5__form"> Confirm Password </h5>
<input type="Password" placeholder="Confirm Password" name="confirmpassword" value={data.confirmpassword} onChange={InputEvent} />
<p>
<button onClick={register} type="submit" className="signup__registerButton" >Register Now</button>
</p>
</form4>
</div>
)
}
export default Register
Make a separate component of History.js
import { createBrowserHistory } from 'history';
export default createBrowserHistory();
Then in Register component.
import history from "../Shared/history";
const formSubmit = e => {
e.preventDefault();
history.push("/SomeComponent", {
someData: true,
otherData:{},
});
};
In Routes:
<Route path="/SomeComponent" component={Component} />

PropType declared function, value is undefined

I'm trying to declare my function from a Action to the PropType but it always display a "...value is undefined". can someone tell where's my error?
I'v tried repack my react folder which is "client" using "npx" and also every related solution.
action/auth.js
import {
LOGIN_SUCCESS,
LOGIN_ERROR,
USER_LOADING,
USER_LOADED,
REGISTER_ERROR,
REGISTER_SUCCESS
} from "./types";
import axios from "axios";
export const getConfig = getState => {
let config = {
headers: { "Content-Type": "application/json" }
};
const token = getState().auth.token;
if (token) {
config.headers["x-auth-token"] = `Bearer ${token}`;
}
return config;
};
export const registerUser = userObj => (dispatch, getState) => {
axios
.post("/auth/register", JSON.stringify(userObj), getConfig(getState))
.then(result => {
console.log(result);
dispatch({
type: LOGIN_SUCCESS,
payload: result.data
});
})
.catch(error => {
console.log(error);
dispatch({
type: LOGIN_ERROR
});
});
};
component/main/RegisterForm
import React, { Component } from "react";
import { Link } from "react-router-dom";
import { Alert } from "reactstrap";
import { registerUser } from "../../actions/auth";
import { connect } from "react-redux";
import PropTypes from "prop-types";
export class RegisterForm extends Component {
constructor(props) {
super(props);
document.title = "OnlineChat - Register";
}
state = {
firstname: "",
lastname: "",
email: "",
password: "",
password1: "",
error: null,
visible: false
};
static propTypes = {
registerUser: PropTypes.func.isRequired
};
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
onDismiss = e => {
this.setState({ visible: false, error: null });
};
onSubmit = e => {
e.preventDefault();
const { firstname, lastname, email, password, password1 } = this.state;
const userObj = this.state;
console.log(firstname, lastname, email, password, password1);
if (!firstname || !lastname || !email || !password || !password1) {
return this.setState({ error: "Please fill all fields.", visible: true });
}
if (password !== password1) {
return this.setState({ error: "Password must match.", visible: true });
}
this.props.registerUser(userObj);
this.setState({
firstname: "",
lastname: "",
email: "",
password: "",
password1: ""
});
};
render() {
const {
firstname,
lastname,
email,
password,
password1,
error,
visible
} = this.state;
return (
<div className="d-flex align-items-center" style={{ height: "100vh" }}>
<div className="container">
<div className="row">
<div className="col-12 col-sm-12 col-md-6 col-lg-6 offset-md-3">
<Alert color="danger" isOpen={visible} toggle={this.onDismiss}>
<strong>Alert! </strong>
{error}
</Alert>
<div className="card">
<div className="card-body">
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label htmlFor="">First Name</label>
<input
type="text"
autoComplete="off"
className="form-control"
onChange={this.onChange}
value={firstname}
name="firstname"
/>
</div>
<div className="form-group">
<label htmlFor="">Last Name</label>
<input
type="text"
autoComplete="off"
className="form-control"
onChange={this.onChange}
value={lastname}
name="lastname"
/>
</div>
<div className="form-group">
<label htmlFor="">Email</label>
<input
type="email"
autoComplete="off"
className="form-control"
onChange={this.onChange}
value={email}
name="email"
/>
</div>
<div className="form-group">
<label htmlFor="">Password</label>
<input
type="password"
autoComplete="off"
className="form-control"
onChange={this.onChange}
value={password}
name="password"
/>
</div>
<div className="form-group">
<label htmlFor="">Re-type Password</label>
<input
type="password"
autoComplete="off"
className="form-control"
onChange={this.onChange}
value={password1}
name="password1"
/>
</div>
<button
className="btn btn-block btn-outline-success"
type="submit"
>
Register
</button>
</form>
<div className="d-block justify-content-left pt-2">
<Link to="/" className="cLink">
Have an account ?
</Link>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
const mapStateToProps = state => ({
auth: state.auth
});
export default connect(
mapStateToProps,
{ registerUser }
)(RegisterForm);
reducer/authReducer
import {
LOGIN_ERROR,
LOGIN_SUCCESS,
REGISTER_ERROR,
REGISTER_SUCCESS,
USER_LOADING
} from "../actions/types";
const initialState = {
token: localStorage.getItem("token"),
isAuthenticated: null,
isLoading: false,
user: null
};
export default (state = initialState, action) => {
switch (action.type) {
case USER_LOADING:
return {
...state,
isLoading: true
};
case LOGIN_SUCCESS:
case REGISTER_SUCCESS:
localStorage.setItem("token", action.payload.token);
return {
...state,
...action.payload,
isAuthenticated: true,
isLoading: false
};
case LOGIN_ERROR:
case REGISTER_ERROR:
return {
...state,
token: null,
isAuthenticated: null,
isLoading: false,
user: null
};
default:
return state;
}
};
Here's the error message keeps prompting in my console.
Error Message
Delete export from class, make it class RegisterForm extends Component { not export class RegisterForm extends Component { since you are exporting the module at the bottom saying export default connect

Where to put proptypes validation?

Im my react application, Im in the refactoring phase. I want to separate redux part from the components. Im confused about where to put proptypes validation? Should the redux props be validated in the container file, and component props should be validated on the component? Or should the both prop types be handled on the component? Or in container? Here is my code.
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import {bindActionCreators} from 'redux';
import { connect } from 'react-redux';
import { registerUser } from '../../../actions';
import { TextFieldGroup } from '../../../components/UI';
class RegisterScreen extends Component {
state = {
name: '',
email: '',
password: '',
password2: '',
errors: {}
};
componentDidMount() {
if (this.props.auth.isAuthenticated) {
this.props.history.push('./dashboard');
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.errors) {
this.setState({ errors: nextProps.errors });
}
}
onChange = e => {
this.setState({
[e.target.name]: e.target.value
});
}
onSubmit = e => {
e.preventDefault();
const newUser = {
name: this.state.name,
email: this.state.email,
password: this.state.password,
password2: this.state.password2
}
this.props.registerUser(newUser, this.props.history);
}
render() {
const { errors } = this.state;
return (
<div className='register'>
<div className='container'>
<div className='row'>
<div className='col-md-8 m-auto'>
<h1 className='display-4 text-center'>Sign Up</h1>
<p className='lead text-center'>
Create Your Developer Connector Account
</p>
<form noValidate onSubmit={this.onSubmit}>
<TextFieldGroup
className={errors.email}
placeholder="* Full Name"
name="name"
value={this.state.name}
onChange={this.onChange}
error={errors.name}
/>
<TextFieldGroup
type='email'
className={errors.email}
placeholder="* Email Address"
name="email"
value={this.state.email}
onChange={this.onChange}
error={errors.email}
info='This site uses Gravatar so if you want a profile image, use a Gravatar email'
/>
<TextFieldGroup
type='password'
className={errors.password}
placeholder="* Password"
name="password"
value={this.state.password}
onChange={this.onChange}
error={errors.password}
/>
<TextFieldGroup
type='password'
className={errors.password2}
placeholder="* Confirm Password"
name="password2"
value={this.state.password2}
onChange={this.onChange}
error={errors.password2}
/>
<input type='submit' className='btn btn-info btn-block mt-4' />
</form>
</div>
</div>
</div>
</div>
);
}
}
RegisterScreen.propTypes = {
registerUser: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired
}
const mapStateToProps = state => ({
auth: state.auth,
errors: state.errors
});
const mapDispatchToProps = dispatch => ({
registerUser: bindActionCreators(registerUser, dispatch)
});
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(RegisterScreen));
You should define the PropTypes in the component as you have in the example there. When deciding when to use PropTypes for static typing, you should always guard against incoming props that can directly affect the desired result of the component when rendered. By that I mean, if the component requires "auth" or "errors" props, then you should define the PropTypes for the component receiving those properties, whether through HoC in this case redux or any other mode of passing data down.

Resources