Converting Class Component to Functional Component with Redux - reactjs

I have this code and wanted to convert to Functional Component. I've tried with setState and when I click login, it just reloads the login page.
class Login extends Component {
state = {
login: '',
password: '',
keepLogged: false
};
changeValue = event => {
event.preventDefault();
const value = event.target.value;
const name = event.target.name;
this.setState({
[name]: value
});
};
checkedValue = event => {
console.log(event.target.checked, event.target.name);
const value = event.target.checked;
const name = event.target.name;
this.setState({
[name]: value
});
};
loginUser = () => {
const { login, password } = this.state;
const { requestSignIn } = this.props;
requestSignIn({ login, password });
};
render() {
const { login, password } = this.state;
return (
<LoginWrapper>
<Containe}>
<Row>
<Col>
<LoginForm>
<FormControl
name='login'
type='text'
placeholder='Username/Email'
value={login}
onChange={this.changeValue}
style={{ marginBottom: '10px' }}
/>
<FormControl
name='password'
type='password'
placeholder='Password'
value={password}
onChange={this.changeValue}
style={{ marginBottom: '10px' }}
/>
<Button
variant='info'
value='Log In'
onClick={() => this.loginUser()}
>
Log In
</Button>
</LoginForm>
</Col>
</Row>
<Row>
<Col>
<LoginBottom
onClick={() => history.push('/registration')}
style={{ marginTop: '30px' }}
>
Need an account?{' '}
<Link style={{ color: '#007bff' }}>Sign Up</Link>
</LoginBottom>
</Col>
</Row>
</Container>
</LoginWrapper>
);
}
}
const mapDispatchToProps = dispatch => ({
requestSignIn: data => dispatch(requestSignIn(data))
});
export default connect(null, mapDispatchToProps)(Login);
This is how far I am right now. And, it does not work.
function Login(props) {
const classes = useStyles();
const [inputs, setInputs] = useState({
// you can login with email or username
login: '',
password: '',
keepLogged: false
});
const { login, password } = inputs;
function handleChange(e) {
event.preventDefault();
const { name, value } = e.target;
setInputs(inputs => ({ ...inputs, [name]: value }));
}
function handleCheck(e) {
console.log(e.target.checked, e.target.name);
const { name, value } = e.target.check;
setInputs(inputs => ({ ...inputs, [name]: value }));
}
const loginUser = () => {
const { login, password } = this.state;
const { requestSignIn } = this.props;
requestSignIn({ setInputs });
};
return (
<LoginWrapper>
<Container>
<Row>
<Col>
<LoginForm>
<FormControl
name='login'
type='text'
placeholder='Username/Email'
value={login}
onChange={handleChange}
/>
<FormControl
name='password'
type='password'
placeholder='Password'
value={password}
onChange={handleChange}
/>
<Button
variant='info'
value='Log In'
onClick={() => this.loginUser()}
>
Log In
</Button>
</LoginForm>
</Col>
</Row>
<Row>
<Col>
<LoginBottom
onClick={() => history.push('/registration')}
style={{ marginTop: '30px' }}
>
Need an account?{' '}
<Link style={{ color: '#007bff' }}>Sign Up</Link>
</LoginBottom>
</Col>
</Row>
</Container>
</LoginWrapper>
);
}
const mapDispatchToProps = dispatch => ({
requestSignIn: data => dispatch(requestSignIn(data))
});
export default connect(null, mapDispatchToProps)(Login);
I am not quite sure, how I can convert this part to functional component :/ How can I convert this to functional component over here?
loginUser = () => {
const { login, password } = this.state;
const { requestSignIn } = this.props;
requestSignIn({ login, password });
};
render() {
const { login, password } = this.state;

You have this local variable for your state:
const [inputs, setInputs] = useState({
// you can login with email or username
login: '',
password: '',
keepLogged: false
});
And your props are on the local variable props.
So all you need to do is use those local variables:
const loginUser = () => {
const { login, password } = inputs;
const { requestSignIn } = props;
requestSignIn({ login, password });
};

Related

After editing data, redux cannot read id

i have a problem.
I use a form to edit my data, then when i want to see edited data, i get an ×
TypeError: Cannot read properties of undefined (reading 'id')
Pointing at my
{users &&
users.map((user) => {
return (
<div key={user.id}>
<Link to={`users/${user.id}`}> {user.name} </Link>
</div>
);
})}
Which is used to display data.
After refreshing the site (F5) it works, so i assume that the redux has problem with reading edited data for the first time, altough it do work with adding new data. anyone know what i can do?
My UserEditForm:
const UserEditForm = () => {
let { id } = useParams();
const { user } = useSelector((state) => state.user);
const [state, setState] = useState({
name: "",
birthday: "",
img: "",
});
const [error, setError] = useState("");
console.log(id);
let history = useHistory();
let dispatch = useDispatch();
const { name, birthday, img } = state;
useEffect(() => {
dispatch(getSingleUser(id));
}, []);
useEffect(() => {
if (user) {
setState({ ...user });
}
}, [user]);
const handleInputChange = (e) => {
let { name, value } = e.target;
setState({ ...state, [name]: value });
};
const handleSubmit = (e) => {
dispatch(updateUser(state, id));
history.push("/");
setError("");
};
return (
<div>
<Button
style={{ width: "100px", marginTop: "20px" }}
variant="contained"
color="secondary"
onClick={() => history.push("/")}
>
Go Back
</Button>
<h2>Edit User</h2>
{error && <h3 style={{ color: "red" }}>{error}</h3>}
<form noValidate autoComplete="off" onSubmit={handleSubmit}>
<TextField
id="standard-basic"
label="Name"
value={name || ""}
name="name"
type="text"
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
label="birthday"
name="birthday"
value={birthday || ""}
type="birthday"
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
label="img"
value={img || ""}
name="img"
type="number"
onChange={handleInputChange}
/>
<Button
style={{ width: "100px" }}
variant="contained"
color="primary"
type="submit"
onChange={handleInputChange}
>
Update
</Button>
</form>
</div>
);
};
export default UserEditForm;
My UserList component:
const UserList = ({ users, history }) => {
const dispatch = useDispatch();
const fetchUsers = async () => {
const response = await axios
.get("http://localhost:3000/characters")
.catch((err) => {
console.log("Err: ", err);
});
dispatch(setUsers(response.data));
};
useEffect(() => {
fetchUsers();
}, []);
console.log(users);
return (
<div>
<button onClick={() => history.goBack()}>...back</button>
<li>
<Link to="/user/add">Add Users</Link>
</li>
{users &&
users.map((user) => {
return (
<div key={user.id}>
<Link to={`users/${user.id}`}> {user.name} </Link>
</div>
);
})}
</div>
);
};
const mapStateToProps = (state) => {
return {
users: state.allUsers.users,
};
};
export default connect(mapStateToProps, null)(UserList);

Can't update the profile picture using cloudinary

I've tried to upload an image in Cloudinary and also want to save it into my database. Uploading an image in Cloudinary works fine but I can't save it into my database. Whenever I tried to do this it's only using the default image I've set in my model. Also likes setPic is working but for a moment and again it's changed to the default image. Please anybody help me figure out this problem.
Please comment if any other details if you need. Please help me.
Here is the Function
const postDetails = (pics) => {
setPicMessage(null);
if (pics?.type === 'image/jpeg' || pics?.type === 'image/png') {
const data = new FormData();
data.append('file', pics);
data.append('upload_preset', 'codeblogger_profile_image');
data.append('cloud_name', 'dhuej17x0');
fetch('https://api.cloudinary.com/v1_1/dhuej17x0/image/upload', {
method: 'post',
body: data,
})
.then((res) => res.json())
.then((data) => {
setPic(data.secure_url.toString());
console.log(pic);
})
.catch((err) => {
toast.error(err);
});
} else {
setPicMessage('Please Select an Image');
toast.error(picMessage);
}
};
And here is the full Profile.js File
import React, { useEffect, useState } from 'react';
import { Button, Col, Container, Form, InputGroup, Row } from 'react-bootstrap';
import { toast, ToastContainer } from 'react-toastify';
import { useDispatch, useSelector } from 'react-redux';
import { getUserDetails, updateUserProfile } from '../actions/userActions';
import { USER_UPDATE_PROFILE_RESET } from '../constant/userConstants';
const Profile = ({ history }) => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [pic, setPic] = useState();
const [password, setPassword] = useState('');
const [picMessage, setPicMessage] = useState();
const [confirmPassword, setConfirmPassword] = useState('');
const [passwordType, setPasswordType] = useState('password');
const [passwordType2, setPasswordType2] = useState('password');
const [showPass, setShowPass] = useState(false);
const [showPass2, setShowPass2] = useState(false);
const dispatch = useDispatch();
const userDetails = useSelector((state) => state.userDetails);
const { user } = userDetails;
// console.log(` this is from line 25 ${user}`);
const userLogin = useSelector((state) => state.userLogin);
const { userInfo } = userLogin;
const userUpdateProfile = useSelector((state) => state.userUpdateProfile);
const { success } = userUpdateProfile;
useEffect(() => {
if (!userInfo) {
history.push('/login');
} else {
if (!user || !user.name || success) {
dispatch({ type: USER_UPDATE_PROFILE_RESET });
dispatch(getUserDetails('profile'));
} else {
setName(user.name);
setEmail(user.email);
setPic(user.pic);
}
}
if (success) {
toast.success('Profile Updated successfully');
}
showPass ? setPasswordType('text') : setPasswordType('password');
showPass2 ? setPasswordType2('text') : setPasswordType2('password');
}, [showPass, showPass2, dispatch, history, success, user, userInfo]);
const postDetails = (pics) => {
setPicMessage(null);
if (pics?.type === 'image/jpeg' || pics?.type === 'image/png') {
const data = new FormData();
data.append('file', pics);
data.append('upload_preset', 'codeblogger_profile_image');
data.append('cloud_name', 'dhuej17x0');
fetch('https://api.cloudinary.com/v1_1/dhuej17x0/image/upload', {
method: 'post',
body: data,
})
.then((res) => res.json())
.then((data) => {
setPic(data.secure_url.toString());
console.log(pic);
})
.catch((err) => {
toast.error(err);
});
} else {
setPicMessage('Please Select an Image');
toast.error(picMessage);
}
};
const submitHandler = (e) => {
e.preventDefault();
if (password !== confirmPassword) {
toast.error('Passwords do not match');
} else {
dispatch(updateUserProfile({ id: user._id, name, email, password }));
}
};
return (
<div className="profilePage mt-4 py-3">
<ToastContainer />
<Container>
<h2>PROFILE</h2>
<Row className="profileContainer">
<Col md={6}>
<Form onSubmit={submitHandler}>
<Form.Group controlId="name" className="mb-2">
<Form.Label>Name</Form.Label>
<Form.Control
type="text"
value={name}
placeholder="Name"
onChange={(e) => setName(e.target.value)}
/>
</Form.Group>
<Form.Group controlId="email" className="mb-2">
<Form.Label>Email</Form.Label>
<Form.Control
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</Form.Group>
<Form.Group controlId="password" className="mb-2">
<Form.Label>New Password</Form.Label>
<InputGroup>
<Form.Control
type={passwordType}
placeholder="New Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<InputGroup.Text>
<i
onClick={() => setShowPass(!showPass)}
className={showPass ? 'fas fa-eye-slash' : 'fas fa-eye'}
style={{ cursor: 'pointer' }}></i>
</InputGroup.Text>
</InputGroup>
</Form.Group>
<Form.Group controlId="confirmPassword" className="mb-2">
<Form.Label>Confirm Password</Form.Label>
<InputGroup>
<Form.Control
type={passwordType2}
placeholder="Confirm Password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
/>
<InputGroup.Text>
<i
onClick={() => setShowPass2(!showPass2)}
className={showPass2 ? 'fas fa-eye-slash' : 'fas fa-eye'}
style={{ cursor: 'pointer' }}></i>
</InputGroup.Text>
</InputGroup>
</Form.Group>
<Form.Group controlId="pic" className="mb-2">
<Form.Label>Change Profile Picture</Form.Label>
<Form.Control
onChange={(e) => postDetails(e.target.files[0])}
type="file"
accept=".jpeg,.png,.jpg"
custom="true"
/>
</Form.Group>
<Button
type="submit"
variant="success"
style={{ letterSpacing: '2px' }}>
UPDATE
</Button>
</Form>
</Col>
<Col
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
<img src={pic} alt={user.name} className="profilePic" />
</Col>
</Row>
</Container>
</div>
);
};
export default Profile;
In submitHandler method, you are not passing pic variable in updateUserProfile.
use this
dispatch(updateUserProfile({ id: user._id, name, email, password, pic }));

Reactjs push route after dispatch

Hello I am having trouble finding where I can call a route with push after authenticating the user
I did it using redux
my action:
const AuthenticateUser = (login, password) => {
    return dispatch => {
        dispatch (startAuth ());
        // fetching data
        api.post ('/ login', {login, password})
            .then (response => {
            localStorage.setItem ('token', response.data [0]);
            dispatch (userAuthenticated (response.data [1]))
        })
            .catch (err => {console.error (err);});
    }
}
export default AuthenticateUser;
my reducer:
const authReducer = (state = initialState, action) => {
    switch (action.type) {
        case USER_AUTHENTICATED:
            return {
                ... state,
                loading: false,
                authenticated: true,
                user: action.user,
            }
        case USER_FAILED_AUTH:
            return {
                ... state,
                loading: false,
                message: action.error
            }
        default:
        return state;
    }
}
and my form
const SignIn = (props) => {
const classes = useStyles();
const dispatch = useDispatch();
const [login, setLogin] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = (e) => {
e.preventDefault()
dispatch(auth(login, password))
}
return (
<div className={classes.root}>
<Grid container spacing={2} className={classes.gridMain}>
<Grid item lg={12} md={12} sm={12} xs={12} align="center">
<img src={require("../nodejs-icon.svg")} alt="bug" height={100} />
</Grid>
<Grid item lg={12} md={12} sm={12} xs={12} className={classes.TextField}>
<form onSubmit={handleSubmit}>
<TextField
className={classes.input2}
id="demo2"
label="Usuário"
variant="outlined"
value={login}
onChange={(e) => setLogin(e.target.value)}
InputLabelProps={{
classes: {
root: classes.label,
focused: classes.focusedLabel,
error: classes.erroredLabel
}
}}
InputProps={{
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
startAdornment: (
<InputAdornment position="start">
<PersonSharpIcon style={{ fontSize: 25, color: 'rgba(20, 176, 12,0.9)' }} />
</InputAdornment>
)
}}
/>
<TextField
className={classes.txtFd}
id="demo2"
label="Senha"
variant="outlined"
value={password}
onChange={(e) => setPassword(e.target.value)}
InputLabelProps={{
classes: {
root: classes.label,
focused: classes.focusedLabel,
error: classes.erroredLabel
}
}}
InputProps={{
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
startAdornment: (
<InputAdornment position="start">
<LockSharpIcon style={{ fontSize: 25, color: 'rgba(20, 176, 12,0.9)' }} />
</InputAdornment>
)
}}
/>
<ButtonBase variant="raised" disableFocusRipple="false" disableRipple="false" centerRipple="false">
<Typography noWrap className={classes.labelForgot} variant="subtitle2">
Esqueci minha senha
</Typography>
</ButtonBase>
<Button type="submit" className={classes.button} variant="raised" disableFocusRipple="false" disableRipple="false" centerRipple="false">
Entrar
</Button>
</form>
</Grid>
I have a route and after I authenticate this user I wanted to send it to a route or display an error msg, but I don't know where in the code to do it and how I would get it.
my route
const AppRouter = () => (
<BrowserRouter>
<Route path="/xd" component={AuthPage} exact={true} />
<Route path="/dashboard/addProduct" component={AddProduct} exact={true} />
</BrowserRouter>
);
So this is in order to give you an answer that is readable instead of using the comments.
In your SignIn component:
import { withRouter } from "react-router-dom";
const SignIn = (props) => {
const { history } = props;
const { push } = history;
// more variables
const handleSubmit = (e) => {
e.preventDefault()
// You pass the push function over here.
dispatch(auth(login, password, push))
}
// Rest of the logic
}
export default withRouter(SignIn);
The withRouter would give you all the props that are coming from react-router, this will allow you to use the history object, which contains the push function, to redirect the user to the page you want.
Then in your authenticate function which I'm guessing is the ´AuthenticateUser´ function you could do this:
const AuthenticateUser = (login, password, push) => {
return dispatch => {
dispatch (startAuth ());
// fetching data
api.post ('/ login', {login, password})
.then (response => {
localStorage.setItem ('token', response.data [0]);
dispatch (userAuthenticated (response.data [1]))
// push goes here
push("/your-awesome-route")
})
.catch (err => {console.error (err);});
}
}
export default AuthenticateUser;
You may use useEffect in SignIn component, which checks for flag authenticated: true (where this variable is passed via props) and does the redirection.
Something like that
useEffect(() => {
const { authenticated, navigation } = props;
if (authenticated) {
navigation.navigate(Routes.GoodPlace);
}
});

How to set resetToken in React+Graphql?

I am having a problem with: my backend generates resetToken for a link in the TriggerResetPassword function after I get a link(http://localhost:3000/reset-password/c10868f7-b64a-4396-925a-3f61468c34ba) where I can change password. But I cannot set the resetToken in my React frontend APP.js. How to make it works?
export const RESET_TOKEN = 'reset-token';
import {GC_USER_ID, RESET_TOKEN} from '../constants'
const resetToken = localStorage.getItem(RESET_TOKEN);
<Route exact path={"/reset-password/:resetToken"} component={ResetPassword}/>
<Route exact path={"/forgot-password"} component={ForgotPassword}/>
And my pages are: ResetPassword
const RESET_PASSWORD = gql 'mutation ($email:String!, $resetToken:String!, $password:String!) { passwordReset(email:$email , password: $password, resetToken: $resetToken){email,name, resetToken}}';
const { email, password, resetToken} = this.state;
return(
<FormControl >
< label htmlFor="password">Password </label>
<TextField type="text" value={this.state.password} onChange={e => {this.setState({ password: e.target.value })
}}
/><br/>
<Mutation mutation={RESET_PASSWORD} variables={{ email, password, resetToken } } onCompleted={() => this._confirm()}>
{mutation => (
<Button onClick={mutation}>Submit
</Button>)}
</Mutation>
</FormControl>
)
}
_confirm = async (resetToken) => {
localStorage.getItem(resetToken);
console.log(resetToken);
this._saveUserData(resetToken);
};
_saveUserData = (id,resetToken) => {
localStorage.setItem(RESET_TOKEN,resetToken);
console.log(resetToken) }
}
and ForgotPassword:
const FORGOT_PASSWORD = gql 'mutation ($email:String!) { triggerPasswordReset(email:$email){ok, resetToken}';
const { email,resetToken} = this.state;
return(
<FormControl >
< label htmlFor="password">Email </label>
<TextField type="text" value={this.state.email} onChange={e => {this.setState({ email: e.target.value })
}}
/><br/>
<Mutation mutation={FORGOT_PASSWORD} variables={{ email } } onCompleted={() => this._confirm()}>
{mutation => (
<Button onClick={mutation}>Submit
</Button>)}
</Mutation>
</FormControl> )
}
_confirm = async data => {
const { resetToken } = this.state.forgotpassword;
this._saveUserData(resetToken);
};
_saveUserData = (resetToken) => {
localStorage.setItem(RESET_TOKEN, resetToken);
}
}

how to remove error messages asynchronously in React

I'm fetching an array of errors, one of them says "Username is taken" and the other one says "Password must be at least 5 chars".
It's displayed like this in React.
{this.props.auth.errors ? (
this.props.auth.errors.map( (err, i) => (
<div key={i} style={{color: 'red'}}>
{err}
</div>
))
):(
null
)}
this.props.auth.errors is an array containing the error messages, after registerUser gets called.
Actions.js
export const registerUser = (userData) => dispatch => {
Axios
.post('/users/register', userData)
.then( res => {
const token = res.data.token;
// console.log(token);
// pass the token in session
sessionStorage.setItem("jwtToken", token);
// set the auth token
setAuthToken(token);
// decode the auth token
const decoded = jwt_decode(token);
// pass the decoded token
dispatch(setCurrentUser(decoded))
// this.props.history.push("/dashboard")
}).catch( err => {
// console.log(err.response.data.error[0].msg)
Object.keys(err.response.data.error).forEach( (key) => {
dispatch({
type: GET_ERRORS,
payload: err.response.data.error[key].msg
})
})
})
};
How would i be able to remove the error, if for example the user does make a password that is minimum of 5 chars, or uses a username that does exist ? You know what i mean ? Also could this be done asynchronously ? As if you were to sign in or register on a top end social media website where it shows the error on async and gos away once you complied to the error message.
Full react code
SignUp.js
import React, { Component } from "react";
import {connect} from 'react-redux';
import {registerUser} from '../actions/authActions';
import TextField from '#material-ui/core/TextField';
import Button from '#material-ui/core/Button';
import Grid from '#material-ui/core/Grid';
import PropTypes from "prop-types";
import Typography from '#material-ui/core/Typography';
class SignUp extends Component{
constructor() {
super();
this.state = {
formData:{
email:'',
username:'',
password:'',
passwordConf: "",
isAuthenticated: false,
},
errors:{},
passErr:null
}
}
componentDidMount() {
// console.log(this.props.auth);
if (this.props.auth.isAuthenticated) {
this.props.history.push("/dashboard");
}
}
// this line is magic, redirects to the dashboard after user signs up
componentWillReceiveProps(nextProps) {
if (nextProps.auth.isAuthenticated) {
this.props.history.push("/dashboard");
}
if (nextProps.errors) {
this.setState({ errors: nextProps.errors });
}
}
handleChange = (e) => {
e.preventDefault();
const {formData} = this.state;
this.setState({
formData: {
...formData,
[e.target.name]: e.target.value
}
});
}
handleSubmit = (e) => {
e.preventDefault();
const {formData} = this.state;
const {username, email, password, passwordConf} = formData;
this.setState({
username: this.state.username,
password: this.state.password,
passwordConf: this.state.passwordConf,
email: this.state.email
});
const creds = {
username,
email,
password
}
console.log(creds);
if (password === passwordConf) {
this.props.registerUser(creds, this.props.history);
} else {
this.setState({passErr: "Passwords Don't Match"})
}
}
render(){
return(
<div>
<Grid container justify="center" spacing={0}>
<Grid item sm={10} md={6} lg={4} style={{ margin:'20px 0px'}}>
<Typography variant="h4" style={{ letterSpacing: '2px'}} >
Sign Up
</Typography>
{this.props.auth.errors ? (
this.props.auth.errors.map( (err, i) => (
<div key={i} style={{color: 'red'}}>
{err}
</div>
))
):(
null
)}
{this.state.passErr && (
<div style={{color: 'red'}}>
{this.state.passErr}
</div>
)}
<form onSubmit={this.handleSubmit}>
<TextField
label="Username"
style={{width: '100%' }}
name="username"
value={this.state.username}
onChange={this.handleChange}
margin="normal"
/>
<br></br>
<TextField
label="Email"
className=""
style={{width: '100%' }}
name="email"
value={this.state.email}
onChange={this.handleChange}
margin="normal"
/>
<br></br>
<TextField
label="Password"
name="password"
type="password"
style={{width: '100%' }}
className=""
value={this.state.password}
onChange={this.handleChange}
margin="normal"
/>
<br></br>
<TextField
label="Confirm Password"
name="passwordConf"
type="password"
style={{width: '100%' }}
className=""
value={this.state.passwordConf}
onChange={this.handleChange}
margin="normal"
/>
<br></br>
<br></br>
<Button variant="outlined" color="primary" type="submit">
Sign Up
</Button>
</form>
</Grid>
</Grid>
</div>
)
}
}
SignUp.propTypes = {
registerUser: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => ({
auth: state.auth
})
const mapDispatchToProps = (dispatch) => ({
registerUser: (userData) => dispatch(registerUser(userData))
})
export default connect(mapStateToProps, mapDispatchToProps)(SignUp)
AuthReducer
import {SET_CURRENT_USER, GET_ERRORS} from '../actions/types';
import isEmpty from '../actions/utils/isEmpty';
const initialState = {
isAuthenticated: false,
errors: []
}
export default (state = initialState, action) => {
switch (action.type) {
case SET_CURRENT_USER:
return{
...state,
isAuthenticated: !isEmpty(action.payload),
user:action.payload
}
case GET_ERRORS:
console.log(action.payload)
// allows for us to loop through an array of errors.
return Object.assign({}, state, {
errors: [...state.errors, action.payload]
})
default:
return state;
}
}
a UI example of how this plays out
Could you clear the errors from your state inside the GET_ERRORS case in your reducer? Basically change your case GET_ERRORS to this:
case GET_ERRORS:
console.log(action.payload)
// allows for us to loop through an array of errors.
return Object.assign({}, state, {
errors: [action.payload]
})
Then in your action creator, do this in your catch instead:
const errors = [];
Object.keys(err.response.data.error).forEach( (key) => {
errors.push(err.response.data.error[key].msg)
})
dispatch({
type: GET_ERRORS,
payload: errors,
})
To get the errors all on individual lines do something like this in your render function:
{this.props.auth.errors ? (
this.props.auth.errors.map( (err, i) => (
<div key={i} style={{color: 'red'}}>
{err}
</div>
<br />
))
):(
null
)}

Resources