React/Redux: redirect after loggin - javascript

Am new to react/redux.I have a Redux action for authentication, and after that I need to redirect to a confirmation page home. I don't know how to redirect
this is my index.js
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl';
import { createStructuredSelector } from 'reselect';
import {loginAction} from './actions';
export class Login extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function
constructor(props) {
super(props);
this.state = {
username: '',
password: ''
};
// this.handleChange = this.handleChangeUsername.bind(this);
// this.handleSubmit = this.handleChangePassword.bind(this);
}
handleChangeUsername(event) {
console.log(event.target.value);
this.setState({username: event.target.value});
console.log(this.state.username)
}
handleChangePassword(event) {
this.setState({password: event.target.value});
console.log(this.state.password)
}
handleSubmit(event) {
this.props.dispatch(loginAction(this.state));
event.preventDefault();
}
render() {
return (
<div>
<div className="loginColumns animated fadeInDown">
<div className="row">
<div className="col-md-6">
</div>
<div className="col-md-6">
<div className="ibox-content">
<form className="m-t" role="form" onSubmit={this.handleSubmit.bind(this)}>
<div className="form-group">
<input type="email" value={this.state.username} onChange={this.handleChangeUsername.bind(this)} className="form-control" placeholder="Username" required="" />
</div>
<div className="form-group">
<input type="password" value={this.state.password} onChange={this.handleChangePassword.bind(this)} className="form-control" placeholder="Password" required="" />
</div>
<button type="submit" className="btn btn-primary block full-width m-b">Login</button>
<a href="#">
<small>Forgot password?</small>
</a>
</form>
</div>
</div>
</div>
<hr/>
<div className="row">
<div className="col-md-6">
Copyright Example Company
</div>
<div className="col-md-6 text-right">
<small>© 2014-2015</small>
</div>
</div>
</div>
</div>
);
}
}
Login.propTypes = {
dispatch: PropTypes.func.isRequired,
};
const mapStateToProps = createStructuredSelector({
// Login: makeSelectLogin(),
});
function mapDispatchToProps(dispatch) {
return {
dispatch,
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);
action.js
import {
DEFAULT_ACTION,
LOGIN_ACTION
} from './constants';
export function defaultAction() {
return {
type: DEFAULT_ACTION,
};
}
export function loginAction(json) {
return {
type: LOGIN_ACTION,
json
};
}
reducer.js
import { fromJS } from 'immutable';
import {
DEFAULT_ACTION,
LOGIN_ACTION
} from './constants';
const initialState = fromJS({
status: false
});
function loginReducer(state = initialState, action) {
console.log("action", action)
switch (action.type) {
case DEFAULT_ACTION:
return state;
case LOGIN_ACTION:
return _testFunction(state,action.json);
default:
return state;
}
}
function _testFunction(state, json) {
if(json.username == "abcd#gmail.com" && json.password == "1234")
return state.set("status", true)
}
export default loginReducer;
i want to redirect /home after successful login. how can i redirect?

Well, what you have to do is something like this. Pass a callback to your action. Once action completed it work, merely invoke that callback, which will programmatically redirect you to the url you need. Upon the submission of the login form pass the input values with the callback function to your action like this.
onSubmit(values) {
this.props.loginAction(values, () => {
this.props.history.push('/');
});
}
Then in your action, if you are calling a backend API, when the promise is resolved make sure you invoke the callback function that gets passed in to the action like this.
export function loginAction(values, callback) {
const request = axios.post(`/endpoint`, values)
.then(() => callback());
return {
type: LOGIN,
payload: request
};
}
This is all what you have to do. It is up to you to make slight alterations to this depending on your scenario and setup. I'll keep it for you as an exercise. Hope this helps. Happy Coding !

Related

how to create login page in react-redux using axios

I've created login page, but my issue is after clicking the submit button it is not redirecting my main Dashboard page.
Authentication/login.js
import React, { Component } from 'react'
import { Field, reduxForm } from 'redux-form';
import renderField from 'components/FormInputs/renderField';
import axios from "axios";
import { Route, router } from 'react-router-dom';
import { withRouter } from 'react-router-dom';
class Login extends Component {
constructor(props) {
super(props)
this.state = {
email: '',
password: '',
}
}
changeHandler = e => {
this.setState({ [e.target.name]: e.target.value })
}
submitHandler = e => {
e.preventDefault()
console.log(this.state)
`axios.post('http://localhost/api/validuser2', {
user: {
"email": this.state.email,
"password": this.state.password
}
},
{ withCredentials: true })`
.then(res => {
console.log(res.data[0])
if (res.data[0] === true) {
alert('Login Successful')
`this.props.handleSuccessfulAuth(res.data[0])`
alert('Logged in')
}
})
.catch(error => {
console.log(error)
})
}
render() {
const { email, password } = this.state
return (
<div className="card">
<div className="header">
<h4>Login</h4>
</div>
<div className="content">
<form className="form-horizontal" onSubmit = {this.submitHandler} >
<div className="form-group">
<label className="control-label col-md-3">Email</label>
<div className="col-md-9">
<Field
name="email"
type="email"
value={email}
//error={errors.email}
component={renderField}
onChange={ this.changeHandler } />
</div>
</div>
<div className="form-group">
<label className="control-label col-md-3">Password</label>
<div className="col-md-9">
<Field
name="password"
type="password"
value={password}
//error={errors.password}
component={renderField}
onChange={ this.changeHandler } />
</div>
</div>
<button className="btn btn-success btn-fill btn-wd">Success</button>
</form>
</div>
</div>
)
}
}
export default reduxForm({
form: 'formElements'
})(Login);
Authentication/index.js
import React, { Component } from 'react';
import Login from './Login';
import Footer from './Footer';
class Authentication extends Component {
constructor(props) {
super(props);
this.handleSuccessfulAuth = this.handleSuccessfulAuth.bind(this);
}
handleSuccessfulAuth(data) {
this.props.handleLogin(data);
`this.props.history.push("../main")`
}
render() {
return (
<div className="wrapper">
<div className="content">
<div className="container-fluid">
<div className="row-md-2">
<div className="col-md-8">
<div className="main-panel">
<Login handleSuccessfulAuth={this.handleSuccessfulAuth} />
</div>
</div>
<div className="main-panel">
<Footer />
</div>
</div>
</div>
</div>
</div>
)
}
}
export default Authentication;
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import registerServiceWorker from './registerServiceWorker';
import { HashRouter } from 'react-router-dom';
import './assets/styles/base.scss';
import 'sweetalert/dist/sweetalert.css';
import Authentication from './pages/Authentication';
import configureStore from './config/configureStore';
import { Provider } from 'react-redux';
const store = configureStore();
const rootElement = document.getElementById('root');
const renderApp = Component => {
ReactDOM.render(
<Provider store={store}>
<HashRouter>
<Component />
</HashRouter>
</Provider>,
rootElement
);
};
renderApp(Authentication);
if (module.hot) {
`module.hot.accept('./pages/Authentication', () => {
const NextApp = require('./pages/Authentication').default
renderApp(NextApp);`
});
}
registerServiceWorker();
can use window.location.href and also this.props.history.push("../dashboard")
submitHandler = e => {
e.preventDefault()
console.log(this.state)
`axios.post('http://localhost/api/validuser2', {
user: {
"email": this.state.email,
"password": this.state.password
}
},
{ withCredentials: true })`
.then(res => {
console.log(res.data[0])
if (res.data[0] === true) {
alert('Login Successful')
//window.location.href = dashboardUrl;
`this.props.handleSuccessfulAuth(res.data[0])`
alert('Logged in')
}
})
.catch(error => {
console.log(error)
})
}

React: How to redirect

I am a beginner in React and was implementing a function where on a button click in the render method, I go to a function foo. In that function, I am sending the username and password to a server.
If the username and password are correct, it returns a JSON object like
{"Result":1,"Cookie":"COOKIE!!!"}
I am trying to redirect it to another class component I have made (Flood) if result is 1. Can someone kindly help me
I tried redirecting it after render and before return but I get an error
Error: Invariant failed: You should not use <Redirect> outside a <Router>
import React from 'react';
import './style.scss';
import LoginImage from './LoginImage.png'
import Button from 'react-bootstrap/Button'
import Form from 'react-bootstrap/Form'
import {Redirect, Router} from 'react-router-dom'
//import Logfailed from './Logfailed'
import Flood from './Flood'
class UserLogin extends React.Component {
constructor(props) {
super(props);
this.state = {userName:'', password:'', act:'l', flag:0, txt:''};
this.handleChange1 = this.handleChange1.bind(this);
this.handleChange2 = this.handleChange2.bind(this);
this.handleClick = this.handleClick.bind(this);
}
async handleClick(e) {
const url = 'http://52.8.557.164/user'
const data = {username:this.state.userName, password:this.state.password, action:this.state.act};
try {
const response = await fetch(url,
{
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
},
});
const json = await response.json();
if(json['Result'] === 1) {
this.setState({flag: 1, txt:''});
}
else {
this.setState({flag:2, txt:'Wrong username and Password'});
}
console.log('Success', JSON.stringify(json));
console.log(json['Cookie']);
} catch (error) {
console.error('Error', error);
}
}
handleChange1(e) {
this.setState({userName: e.target.value})
}
handleChange2(e) {
this.setState({password: e.target.value})
}
render() {
if (this.state.flag === 1) {
return <Redirect to='/Flood' />
}
return (
<div className = 'outer-container' ref={this.props.containerRef}>
<div className = 'header'> Login </div>
<div className="content">
<div className="image">
<img src={LoginImage} />
</div>
<Form className = 'form'>
<Form.Group controlId="formBasicEmail" className = 'form-group'>
<Form.Label style={{marginTop: '90px'}}>Username</Form.Label>
<Form.Text className="text-muted" htmlFor="username"></Form.Text>
<input type="text" value = {this.state.userName} name="username" placeholder="username" onChange={this.handleChange1}/>
</Form.Group>
<Form.Group controlId="formBasicPassword" className = 'form-group'>
<Form.Label>Password</Form.Label>
<Form.Text className="text-muted" htmlFor="password"></Form.Text>
<input type="password" value = {this.state.password} name="password" placeholder="password" onChange={this.handleChange2} />
<br></br>
<span>{this.state.txt}</span>
</Form.Group>
</Form>
</div>
<div className="footer">
<Button variant="outline-primary" size="lg" onClick={this.handleClick} className="btn" block>
Login
</Button>
</div>
</div>
);
}
}
export default UserLogin;
import React from 'react';
class Flood extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<h1>gg</h1>
)}
}
export default Flood;
import React from 'react';
import './App.css';
import UserLogin from './UserLogin';
import Register from './Register'
import { Router, Redirect} from 'react-router-dom'
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
login: true
};
}
componentDidMount() {
this.rightSide.classList.add("right");
}
changeState() {
const { login } = this.state;
if (login) {
this.rightSide.classList.remove("right");
this.rightSide.classList.add("left");
} else {
this.rightSide.classList.remove("left");
this.rightSide.classList.add("right");
}
this.setState(prevState => ({ login: !prevState.login }));
}
render() {
const {login} = this.state;
const curr = login ? "Register" : "Login";
const currentActive = login ? "login" : "register";
return (
<div className="App">
<div className="login">
<div className="container" ref={ref => (this.container = ref)}>
{login && (
<UserLogin containerRef={ref => (this.curr = ref)} />
)}
{!login && (
<Register containerRef={ref => (this.curr = ref)} />
)}
</div>
<RightSide
curr={curr}
currentActive={currentActive}
containerRef={ref => (this.rightSide = ref)}
onClick={this.changeState.bind(this)}
/>
</div>
</div>
);
}
}
const RightSide = props => {
return (
<div
className="right-side"
ref={props.containerRef}
onClick={props.onClick}
>
<div className="inner-container">
<div className="text">{props.curr}</div>
</div>
</div>
);
};
export default App;
BrowserRouter is the provider to be used in React Router for usage of anything related to routing. To add it to your component:
import { BrowserRouter as Router } from "react-router-dom";
class App extends React.Component {
render() {
return (
<Router>
// Rest of the App component here.
</Router>
);
}
}
Note that there needs to be only one wrapping Router in an application (generally) and hence it makes sense to wrap the entry component in it.
Basic Routing Example - React Routing
First of all, you need to wrap your component using withRouter tag
import { withRouter } from 'react-router-dom'
then wrap your component/class when you're exporting
export default withRouter(yourComponent);
ok, now back to the issue:
To redirect, you can simply push something to the history object
history.push('/redirect-location');

Cannot destructure property `user` of 'undefined' or 'null'

Error retrieving user information with redux.
I want to get the user information (name, password and address of the avatar from the db) and then edit it.
I'm using nodejs, express, react, redux and jwt.
Actions/user.js
import axios from 'axios';
import {setAlert} from './alert';
import {GET_USER, USER_ERROR} from './types';
//Get current users profile
export const getCurrentUser = () => async dispatch => {
try {
const res = await axios.get('/api/users/me');
dispatch({
type: GET_USER,
payload: res.data
});
} catch (err) {
dispatch({
type:USER_ERROR,
payload:{msg: err.response.statusText, status: err.response.status}
});
}
};
Reducers/user.js
import {GET_USER, USER_ERROR, CLEAR_USER} from '../actions/types';
const initialState = {
user: null,
users: [],
loading: true,
error: {}
}
export default function(state = initialState, action) {
const {type, payload} = action;
switch(type){
case GET_USER:
return{
...state,
loading:false,
user:payload
};
case USER_ERROR:
return{
...state,
error:payload,
loading: false
};
default:
return state;
}
}
Components/edituser/EditUser.js
import React, {useState, Fragment, useEffect} from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {getCurrentUser} from '../../actions/user';
import {Link, withRouter} from 'react-router-dom';
import Alert from '../layout/Alert';
import InputSelector from '../util/InputSelector';
const EditUser = ({
user:{user,loading},
getCurrentUser,
history}) => {
const [formData, setFormData] = useState({
name: '',
email: '',
password: ''
});
useEffect(()=>{
getCurrentUser();
});
return (
<Fragment>
<div className="col-md-12 mb-3">
<div className="card">
<div className="card-body">
<div className="row">
<div className="col-md-3 d-flex align-items-center">
<div className="img">
<img className="img-fluid" src={'/uploads/noImg.jpg'} />
</div>
</div>
<div className="col-md-9">
<form>
<div className="form-group">
<label><i className="fas fa-user"></i> Username</label>
<input
type="text"
name="skills"
className="form-control"
placeholder="Edita tu nombre de usuario"
/>
</div>
<div className="form-group">
<label><i className="fas fa-envelope"></i> Email</label>
<input
type="text"
name="skills"
className="form-control"
placeholder="Edita tu email"
/>
</div>
<div className="form-group">
<label><i className="fas fa-key"></i> Contraseña</label>
<input
type="text"
name="skills"
className="form-control"
placeholder="Edita tu nombre de contraseña"
/>
</div>
<div className="form-group" >
<label><i class="fas fa-upload"></i> Imagen De Perfil</label>
<InputSelector/>
</div>
<div className="col-md-12 text-center">
<button className="btn btn-primary btn-block"><i class="fas fa-check"></i> Guardar</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</Fragment>
);
};
EditUser.propTypes = {
getCurrentUser: PropTypes.func.isRequired,
user: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
user: state.user
});
export default connect(mapStateToProps, {getCurrentUser})
(withRouter(EditUser));
https://imgur.com/xLzAu1A
The problem always happens when I write user: {user, loading}, when I put another code that I already have done it works fine, but whenever I write that the page fails.
cannot destructure property user of 'undefined' or 'null'. This mean user data null or undefined at the first time when you use fetch data from server. The API call to server is async. At the second time, you will got user data.
I see the user that you take as props with redux is res.data from server. I'm uncertain structure of res.data what is? So in component, you should be do like:
const EditUser = ({
user,
getCurrentUser,
history
}) => {
if (user) {
const { loading, ... } = user // Get another key in user object
}
...
...
...
// When you try to destructure action object by default for the first time it would not have contain any keys defined by us, However it would contain default keys that redux provides. While Destructring this object would result in undefined or null because there is no matching key. So destructure inside the condition where it matches.
export const addBug = desc => ({
type: actions.BUG_ADDED,
payload: {
description: desc
}
});
// i am dispatching the action in the below line
store.dispatch(addBug('button is not clickable'));
// below i have destructred the action.payload object
let lastId = 0;
function reducer(state = [], action) {
console.log(action);
switch(action.type) {
case actions.BUG_ADDED:
const {description} = action.payload;
return [
...state,
{
id: ++lastId,
description,
resolved: false,
},
];
case actions.BUG_REMOVED:
return state.filter(bug => action.payload.id !== bug.id);
default: return state;
}
}
export default reducer;

Redux forms: how to handle errors in form component

Now I have such error:
Unhandled Rejection (SubmissionError): Submit Validation Failed
27 | .catch(err => {
> 28 | return ErrorHandler.raiseAnError(err);
29 | });
Here is my code:
TractorForm.js
import React, { Component } from "react";
import PropTypes from "prop-types";
import { reduxForm } from "redux-form";
import FormInput from "../Shared/FormInput";
import GlobalConst from "../GlobalConst";
import { Link } from "react-router-dom";
import SelectInput from "../Shared/SelectInput";
import ErrorHandler from "../ErrorHandler";
const manufacturers = ["DAF", "VOLVO", "SCANIA", "MAN", "IVECO"];
class TractorFormWrapper extends Component {
state = {
loading: false,
isSubmitted: false
};
onFormSubmit = e => {
e.preventDefault();
this.setState({ isSubmitted: true });
if (this.props.valid) {
this.setState({ loading: true });
this.props
.handleSubmit(e)
.then(() => alert("is ok!"))
.catch(err => {
return ErrorHandler.raiseAnError(err);
});
}
};
render() {
const { submitText, error } = this.props;
const { loading, isSubmitted } = this.state;
const formClassNames = loading ? "ui form loading" : "ui form";
return (
<form className={formClassNames} onSubmit={this.onFormSubmit}>
<div className="ui grid fields">
<div className="sixteen wide eight wide computer column">
<SelectInput
name="manufacturer"
type="text"
label="Производитель"
validations={[GlobalConst.REQUIRED]}
isSubmitted={isSubmitted}
values={manufacturers}
/>
</div>
<div className="sixteen wide eight wide computer column">
<FormInput
name="model"
type="text"
label="Модель"
validations={[GlobalConst.REQUIRED]}
isSubmitted={isSubmitted}
/>
</div>
<div className="sixteen wide column">
<FormInput
name="description"
type="textarea"
label="Описание"
isSubmitted={isSubmitted}
/>
</div>
</div>
{error && (
<div className="ui red message">
<strong>{error}</strong>
</div>
)}
<div className="ui fluid buttons">
<button
className="ui primary button"
type="submit"
disabled={loading}
>
{submitText}
</button>
<Link to="/tractors" className="ui button">
Отмена
</Link>
</div>
</form>
);
}
}
let TractorForm = {};
TractorForm.propTypes = {
submitText: PropTypes.string
};
TractorForm.defaultProps = {
submitText: "Отправить"
};
TractorForm = reduxForm({
form: "tractor"
})(TractorFormWrapper);
export default TractorForm;
TractorAdd.js
import React, { Component } from "react";
import TractorForm from "./TractorForm";
import TractorApi from "./TractorApi";
import { toast } from "react-semantic-toasts";
import ErrorHandler from "../ErrorHandler";
class TractorAdd extends Component {
state = {};
submit = values =>
TractorApi.create(values).then(
() => {
toast({
type: "success",
icon: "truck",
title: "Тягач создан",
description: ""
});
this.props.history.push("/tractors");
},
error => {
return Promise.reject(error);
}
);
render() {
return (
<div>
<TractorForm onSubmit={this.submit} submitText="Создать" />
</div>
);
}
}
export default TractorAdd;
ErrorHandler.js
import { SubmissionError } from "redux-form";
export default {
raiseAnError: error => {
if (
error.response.data.hasOwnProperty("message") &&
error.response.data.hasOwnProperty("stackHighlighted")
) {
throw new SubmissionError({
_error: error.response.data.hasOwnProperty("message") || "error"
});
} else {
const errKeys = Object.keys(error.response.data);
const errObj = {};
for (const errItem of errKeys) {
errObj[errItem] = error.response.data[errItem]["message"];
}
errObj["_error"] = "Произошла ошибка!";
throw new SubmissionError(errObj);
}
}
};
why do I need this in form instead of add component? so I can fix logic with loading state variable and re-submit form
also my _error isn't working for some reasons, but I've done everything as in doc: https://redux-form.com/7.3.0/examples/submitvalidation/
what I do wrong and how to handle SubmissionError in form component?
The reason your error handling is not working is because you should throw new SubmissionError in the handleSubmit function itself, like the example you linked:
<form onSubmit={handleSubmit(submit)}>
function submit(values) {
return sleep(1000).then(() => {
// If error
throw new SubmissionError({
password: 'Wrong password',
_error: 'Login failed!'
})
// The rest logic here ...
})
}
So you should refactor your code a little bit, something like that (follow the comments):
<form className={formClassNames} onSubmit={handleSubmit(values => {
// 1. Your submit logic should be here.
// 2. Better to organize it in a stand-alone function, as `submit` function from the above example.
// 3. If you throw SubmissionError here, the error handling will work.
throw new SubmissionError({
_error: 'Error'
})
)}>
Try to tune-up and simplify your code, like the official library example you provided.
Update 1 - almost a complete example. Please follows the comments strictly:
* I removed some unrelated to the problem code blocks
TractorForm - it will be reused for both Edit and Add (Create) actions.
class TractorForm extends Component {
render() {
const { handleSubmit, error } = this.props;
return (
<form onSubmit={handleSubmit}>
// Rest input fields should be here ...
{ error && (
<div className="ui red message">
<strong>{error}</strong>
</div>
)}
<div className="ui fluid buttons">
<button
className="ui primary button"
type="submit"
disabled={loading}
>
{submitText}
</button>
</div>
</form>
);
}
}
export default reduxForm({
form: "tractor"
})(TractorForm);
TractorAdd - For adding a new Tractor. The same logic, you can apply for Edit Tractor. You have to create a new TractorEdit component, that will pass down onSubmit function to TractorForm.
class TractorAdd extends Component {
onSubmit (values) {
// Please make sure here you return the promise result. It's a `redux-form` gotcha.
// If you don't return it, error handling won't work.
return TractorApi.create(values).then(
() => {
toast({
type: "success",
icon: "truck",
title: "Тягач создан",
description: ""
});
this.props.history.push("/tractors");
},
error => {
// 1. Here you should throw new SubmissionError.
// 2. You should normalize the error, using some parts of `ErrorHandler` function
throw new SubmissionError(error)
}
);
}
render() {
return <div>
<TractorForm onSubmit={this.onSubmit} submitText="Создать" />
</div>
}
}
export default TractorAdd;
Update 2 - keep you implementation as it is, but change a little bit your TractorFormWrapper onFormSubmit and its usage:
Documentation explanations here.
TractorForm
class TractorFormWrapper extends Component {
state = {
loading: false,
isSubmitted: false
};
onFormSubmit = data => {
this.setState({ isSubmitted: true });
if (this.props.valid) {
this.setState({ loading: true });
// `onSubmit` comes from `TractorAdd`
return this.props.onSubmit(data)
.then(() => alert("is ok!"))
.catch(err => {
return ErrorHandler.raiseAnError(err);
});
}
};
render() {
const { handleSubmit } = this.props
return <form onSubmit={handleSubmit(this.onFormSubmit)}>The rest logic is here ...</form>
}
}
let TractorForm = {};
TractorForm.propTypes = {
submitText: PropTypes.string
};
TractorForm.defaultProps = {
submitText: "Отправить"
};
TractorForm = reduxForm({
form: "tractor"
})(TractorFormWrapper);
export default TractorForm;

How to update state in react-redux?

I have made a submit form. I have made userReducer where user[] is array and each array element has firstname, lastname,emailid etc. When I click on submit button it shows array element [0] but when I click on clear button and again try to fill in the form and try to submit no user is added again i.e no state is updated. How to fix this problem ?
Form component (form.js) :
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as action from '../actions/actions';
import './form.css';
class Form extends Component {
constructor(props) {
super(props);
this.setFirstName = this.setFirstName.bind(this);
this.setLastName = this.setLastName.bind(this);
this.setEmailId = this.setEmailId.bind(this);
this.setIban = this.setIban.bind(this);
this.setBankName = this.setBankName.bind(this);
this.showUser = this.showUser.bind(this);
this.reset = this.reset.bind(this);
console.log(this.props);
}
setFirstName(event) {
this.props.dispatch(action.setFirstName(event.target.value));
}
setLastName(event) {
this.props.dispatch(action.setLastName(event.target.value));
}
setEmailId(event) {
this.props.dispatch(action.setEmailId(event.target.value));
}
setIban(event) {
this.props.dispatch(action.setIban(event.target.value));
}
setBankName(event) {
this.props.dispatch(action.setBankName(event.target.value));
}
showUser(){
const jsonobj = this.props;
alert(JSON.stringify(jsonobj));
}
reset(){
this.props.dispatch(action.setFirstName(''));
this.props.dispatch(action.setLastName(''));
this.props.dispatch(action.setEmailId(''));
this.props.dispatch(action.setIban(''));
this.props.dispatch(action.setBankName(''));
}
render(){
return(
<div>
<div id="center">
<form>
<div className="form-group">
<label htmlFor="firstname">First Name:</label>
<input type="firstname" className="form-control" id="firstname" value={this.props.firstname} onChange={this.setFirstName} required/>
</div>
<div className="form-group">
<label htmlFor="lastname">Last Name:</label>
<input type="lastname" className="form-control" id="lastname" value={this.props.lastname} onChange={this.setLastName} required/>
</div>
<div className="form-group">
<label htmlFor="email">Email address:</label>
<input type="email" className="form-control" id="email" value={this.props.emailid} onChange={this.setEmailId} required/>
</div>
<div className="form-group">
<label htmlFor="bankacc">IBAN:</label>
<div id="deletebank" className="items">
<input type="bankacc" className="form-control" id="bankacc" value={this.props.iban} onChange={this.setIban} required/>
<button type="button" className="btn btn-default btn-sm">
<span className="glyphicon glyphicon-trash"></span>
</button>
</div>
</div>
<div className="form-group">
<label htmlFor="bankname">Bank Name:</label>
<input type="bankname" className="form-control" id="bankname" value={this.props.bankname} onChange={this.setBankName} required/>
</div>
<div className="form-group">
<div id="buttons" className="items">
<button type="button" class="btn btn-warning" onClick={this.reset}>Clear Input</button>
<button type="button" className="btn btn-success" onClick={this.showUser}>Submit</button>
</div>
</div>
</form>
</div>
</div>
)}
}
const mapStateToProps = store => {
return {
firstname: store.user.firstname,
lastname: store.user.lastname,
emailid: store.user.emailid,
iban: store.user.iban,
bankname: store.user.bankname
}
}
export default connect(mapStateToProps)(Form);
reducer.js:
const userReducer = (state = {
user:[{
firstname:'',
lastname:'',
emailid:'',
bankaccounts:{
iban:'',
bankname:''
}
}]
}, action) => {
switch (action.type) {
case 'SET_FIRSTNAME':{
return {
...state,
user:{...state.user, firstname: action.payload}
}
}
case 'SET_LASTNAME':{
return {
...state,
user:{...state.user, lastname: action.payload}
}
}
case 'SET_EMAILID':{
return {
...state,
user:{...state.user, emailid: action.payload}
}
}
case 'SET_IBAN':{
return {
...state,
user:{...state.user, iban: action.payload}
}
}
case 'SET_BANKNAME':{
return {
...state,
user:{...state.user, bankname: action.payload}
}
}
default: return state;
}
}
export default userReducer;
Actions.js:
export const SET_FIRSTNAME = 'SET_FIRSTNAME';
export const SET_LASTNAME = 'SET_LASTNAME';
export const SET_EMAILID = 'SET_EMAILID';
export const SET_IBAN = 'SET_IBAN';
export const SET_BANKNAME = 'SET_BANKNAME';
export function setFirstName(firstname){
return {
type:SET_FIRSTNAME,
payload:firstname
}
}
export function setLastName(lastname){
return {
type:SET_LASTNAME,
payload:lastname
}
}
export function setEmailId(emailid){
return {
type:SET_EMAILID,
payload:emailid
}
}
export function setIban(iban){
return {
type:SET_IBAN,
payload:iban
}
}
export function setBankName(bankname){
return {
type:SET_BANKNAME,
payload:bankname
}
}
store.js:
import { createStore } from 'redux';
import userReducer from './reducers/reducers';
const store = createStore(userReducer);
store.subscribe(() => {
console.log('Store changed', store.getState());
})
export default store;
Screenshot:
There's a bunch of stuff to address here, but the primary issue is that your state is expecting user to be an array. I think it would be very wise to rename this users as to not get confused:
(I'm going to remove some keys to make this easier)
const initialState = {
users: [ // note "users" not "user"
{
firstname: '',
lastname: '',
},
],
};
Your reducer switch statements don't specify WHICH user it should be updating. If you want to just start with "adding" a new user it might look something like this:
const userReducer = (state = initialState, action) => {
switch (action.type) {
case "ADD_USER": {
return {
...state,
users: [...state.users, action.payload],
};
}
default:
return state;
}
};
Here we add a new user to the users array in the form of action.payload which should contain all the keys you want on your user.
You can now have an action creator that's a bit more concise
const addUser = user => ({
type: 'ADD_USER',
payload: user,
})
And your form could be simplified a lot:
import * as actions from './actions'
class Form extends React.Component {
state = {
firstname: '',
lastname: '',
}
render() {
return (
<form onSubmit={() => {
this.props.dispatch(actions.addUser(this.state))
}}>
<input
value={this.state.firstname}
onChange={e => this.setState({ firstname: e.target.value })
/>
<input
value={this.state.lastname}
onChange={e => this.setState({ lastname: e.target.value })
/>
</form>
)
}
}
export default connect()(Form)

Categories