Redux not reaching the action - reactjs

Here is the login.js file
import {Form, Icon, Input, Button} from 'antd';
import React from 'react'
import axios from 'axios'
import {connect} from 'react-redux'
import {loading} from '../actions/authenticationActions'
class Login extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
return this.props.onloading;
};
render() {
const { getFieldDecorator } = this.props.form;
return (
<div className={'ant-col-12 ant-col-offset-6'} style={{ display: 'inline-flex', justifyContent: 'center', alignItems: 'center', height: "100vh"}}>
<Form onSubmit={this.handleSubmit} className="login-form" style={{width: "300px"}}>
<Form.Item>
{getFieldDecorator('userName', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" />
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
})(
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="Password" />
)}
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" className="login-form-button" style={{width: "100%"}}>
Log in
</Button>
</Form.Item>
</Form>
</div>
);
}
}
const WrappedLogin = Form.create({ name: 'normal_login' })(Login);
const mapActionsToProps = {
onloading: loading
};
export default connect(null, mapActionsToProps)(WrappedLogin);
and here is the Actions file:
import {LOADING} from "../utils/ActionTypes";
export function loading() {
console.log("action received");
return {
type: LOADING
}
}
also here is the Reducers file:
import {LOADING} from "../utils/ActionTypes";
const initialState= [{
Authorized: false,
user: null,
token: null,
loading: false
}];
export default function authenticationReducer(state = initialState, action) {
switch (action.type) {
case LOADING:
return console.log("loading....");
default:
return state;
}
}
and finally the Store file:
import {combineReducers, createStore, compose} from "redux";
import authenticationReducer from "../reducers/authenticationReducer";
const store = createStore(authenticationReducer, compose(
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
));
export default store;
hi, I have just started learning redux and I have this issue where as you can see in the actions file there is a console message the problem is I'm not reaching that point and I don't know why any help is appreciated...

You're not calling your action this.props.onloading anywhere in your code. Calling it in the method will dispatch the corresponding action.
handleSubmit = (e) => {
e.preventDefault();
this.props.onloading()
};

Related

How would I go about setting up this modal to toggle?

I'm trying to get an editModal and a detailsModal to open on click. I set up actions and reducers for the modal so it can be stored in the global state and it works, but currently the modals are set to open automatically and I cannot close them. I believe it's something wrong with my logic, but it seems like it would be rather straightforward. Does anyone have any tips on how to complete this?
modalReducer.js
import { OPEN_MODAL } from "../actions/types";
const initialState = {
modal: false,
};
export default function (state = initialState, action) {
switch (action.type) {
case OPEN_MODAL:
return {
...state,
modal: false,
};
default:
return state;
}
}
ClientEditModal.js
import React, { Component } from "react";
import {
Button,
Modal,
ModalHeader,
ModalBody,
Form,
FormGroup,
Label,
Input,
} from "reactstrap";
import { connect } from "react-redux";
import { editClient } from "../actions/clientActions";
import { openModal } from "../actions/modalActions";
import PropTypes from "prop-types";
class ClientEditModal extends Component {
componentDidMount() {
this.props.editClient();
this.props.openModal();
}
toggle = () => {
this.setState({
modal: !this.props.modal,
});
};
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
onSubmit = (e) => {
e.preventDefault();
// Close modal
this.toggle();
};
displayClient = (clients, _id) => {
return (
<FormGroup key={_id} timeout={500} classNames="fade">
<Label for="name"> Name </Label>
<Input
type="text"
name="name"
id="client"
value={clients.name}
onChange={this.onChange}
></Input>
<Label for="email"> Email </Label>
<Input
type="text"
name="email"
id="client"
value={clients.email}
onChange={this.onChange}
></Input>
<Label for="number"> Number </Label>
<Input
type="text"
name="number"
id="number"
value={clients.number}
onChange={this.onChange}
></Input>
<Button color="dark" style={{ marginTop: "2rem" }} block>
Submit Client Edit
</Button>
</FormGroup>
);
};
render() {
const { clients } = this.props.client;
return (
// Split button into separate component
<div>
<Button
color="dark"
style={{ marginBottom: "2rem", marginLeft: "1rem" }}
onClick={this.toggle}
>
Edit
</Button>
<Modal
isOpen={this.props.modal}
toggle={this.toggle}
style={{ padding: "50px" }}
>
<ModalHeader toggle={this.toggle}> Edit</ModalHeader>
<ModalBody>
<Form onSubmit={this.onSubmit}>
{clients.map(this.displayClient)}
</Form>
</ModalBody>
</Modal>
</div>
);
}
}
ClientEditModal.propTypes = {
editClient: PropTypes.func.isRequired,
client: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => ({
client: state.client,
modal: state.modal,
});
export default connect(mapStateToProps, { editClient, openModal })(
ClientEditModal
);
modalActions.js
import { OPEN_MODAL } from "./types";
export const openModal = () => {
return {
type: OPEN_MODAL,
};
};
The main issue is - your toggle function, !this.props.modal will invert the value of modal and the component always holds the value of true.
So, one option is to maintain another action for closing modal.
See the updated code snippets below.
Reducer
import { OPEN_MODAL } from "../actions/types";
const initialState = {
modal: false,
};
export default function (state = initialState, action) {
switch (action.type) {
case OPEN_MODAL:
return {
...state,
modal: false,
};
case CLOSE_MODAL:
return {
...state,
modal: true,
};
default:
return state;
}
}
Actions
import { OPEN_MODAL } from "./types";
export const openModal = () => {
return {
type: OPEN_MODAL,
};
};
export const closeModal = () => {
return {
type: CLOSE_MODAL,
};
};
ClientModal.js
import React, { Component } from "react";
import {
Button,
Modal,
ModalHeader,
ModalBody,
Form,
FormGroup,
Label,
Input,
} from "reactstrap";
import { connect } from "react-redux";
import { editClient } from "../actions/clientActions";
import { openModal } from "../actions/modalActions";
import PropTypes from "prop-types";
class ClientEditModal extends Component {
componentDidMount() {
this.props.editClient();
this.props.openModal();
}
toggle = () => {
// this.setState({ //<---- setstate is not required as once the state in the store is updated, then the component is re-rendered automatically
// modal: !this.props.modal, //<---- once toggle is executed - it is always true
//});
this.props.closeModal()
};
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
onSubmit = (e) => {
e.preventDefault();
// Close modal
this.toggle();
};
displayClient = (clients, _id) => {
return (
<FormGroup key={_id} timeout={500} classNames="fade">
<Label for="name"> Name </Label>
<Input
type="text"
name="name"
id="client"
value={clients.name}
onChange={this.onChange}
></Input>
<Label for="email"> Email </Label>
<Input
type="text"
name="email"
id="client"
value={clients.email}
onChange={this.onChange}
></Input>
<Label for="number"> Number </Label>
<Input
type="text"
name="number"
id="number"
value={clients.number}
onChange={this.onChange}
></Input>
<Button color="dark" style={{ marginTop: "2rem" }} block>
Submit Client Edit
</Button>
</FormGroup>
);
};
render() {
const { clients } = this.props.client;
return (
// Split button into separate component
<div>
<Button
color="dark"
style={{ marginBottom: "2rem", marginLeft: "1rem" }}
onClick={this.toggle}
>
Edit
</Button>
<Modal
isOpen={this.props.modal}
toggle={this.toggle}
style={{ padding: "50px" }}
>
<ModalHeader toggle={this.toggle}> Edit</ModalHeader>
<ModalBody>
<Form onSubmit={this.onSubmit}>
{clients.map(this.displayClient)}
</Form>
</ModalBody>
</Modal>
</div>
);
}
}
ClientEditModal.propTypes = {
editClient: PropTypes.func.isRequired,
client: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => ({
client: state.client,
modal: state.modal,
});
export default connect(mapStateToProps, { editClient, openModal, closeModal })(
ClientEditModal
);

Was Form.create() from antd replaced?

i am trying to create a login page in react using antd. I found a tutorial for doing this,but i belive that it is outdated, because it gives an error. I read on a forum that form.create() is not available anymore, but i don't know how to replace it.Here is my code:
import { Form, Icon, Input, Button, Spin } from 'antd';
import { connect } from 'react-redux';
import { NavLink } from 'react-router-dom';
import * as actions from '../store/actions/auth';
const FormItem = Form.Item;
const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />;
class NormalLoginForm extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
this.props.onAuth(values.userName, values.password);
this.props.history.push('/');
}
});
}
render() {
let errorMessage = null;
if (this.props.error) {
errorMessage = (
<p>{this.props.error.message}</p>
);
}
const { getFieldDecorator } = this.props.form;
return (
<div>
{errorMessage}
{
this.props.loading ?
<Spin indicator={antIcon} />
:
<Form onSubmit={this.handleSubmit} className="login-form">
<FormItem>
{getFieldDecorator('userName', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
})(
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="Password" />
)}
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" style={{marginRight: '10px'}}>
Login
</Button>
Or
<NavLink
style={{marginRight: '10px'}}
to='/signup/'> signup
</NavLink>
</FormItem>
</Form>
}
</div>
);
}
}
const WrappedNormalLoginForm = Form.create()(NormalLoginForm);
const mapStateToProps = (state) => {
return {
loading: state.loading,
error: state.error
}
}
const mapDispatchToProps = dispatch => {
return {
onAuth: (username, password) => dispatch(actions.authLogin(username, password))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(WrappedNormalLoginForm);
When i try to run it, i get an error that says:
TypeError: _antd.Form.create(...) is not a function
How can i rewrite the code in order to make it run?
AntD has removed Form.create in v4 and you can replace the above code with the modified API structure like
class NormalLoginForm extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
this.props.onAuth(values.userName, values.password);
this.props.history.push('/');
}
});
}
render() {
let errorMessage = null;
if (this.props.error) {
errorMessage = (
<p>{this.props.error.message}</p>
);
}
const { getFieldDecorator } = this.props.form;
return (
<div>
{errorMessage}
{
this.props.loading ?
<Spin indicator={antIcon} />
:
<Form onSubmit={this.handleSubmit} className="login-form">
<FormItem name='userName' rules={[{ required: true, message: 'Please input your username!' }]}>
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" />
</FormItem>
<FormItem name="password" rules={[{ required: true, message: 'Please input your Password!' }]}>
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="Password" />
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" style={{marginRight: '10px'}}>
Login
</Button>
Or
<NavLink
style={{marginRight: '10px'}}
to='/signup/'> signup
</NavLink>
</FormItem>
</Form>
}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
loading: state.loading,
error: state.error
}
}
const mapDispatchToProps = dispatch => {
return {
onAuth: (username, password) => dispatch(actions.authLogin(username, password))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(NormalLoginForm);
Please see the migration guidelines for more details
I think you are using Antd v4.*. Form.create({}) is no more in latest version, so you have to your code as follow to make it working. V4 has. major changes so you have to go through migration guidelines
import { Form, Input, Button, Spin } from 'antd';
import { LoadingOutlined, UserOutlined, LockOutlined } from "#ant-design/icons";
import { connect } from 'react-redux';
import { NavLink } from 'react-router-dom';
import * as actions from '../store/actions/auth';
const FormItem = Form.Item;
const antIcon = <LoadingOutlined style={{ fontSize: 24 }} />;
class NormalLoginForm extends React.Component {
handleFinish = (values) => {
this.props.onAuth(values.userName, values.password);
this.props.history.push('/');
}
render() {
let errorMessage = null;
if (this.props.error) {
errorMessage = (
<p>{this.props.error.message}</p>
);
}
return (
<div>
{errorMessage}
{
this.props.loading ?
<Spin indicator={antIcon} />
:
<Form onFinish={this.handleFinish} className="login-form">
<FormItem name="userName" rules={[{ required: true, message: 'Please input your username!' }]}>
<Input prefix={<UserOutlined style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" />
)}
</FormItem name="password" rules={[{ required: true, message: 'Please input your Password!' }]}>
<FormItem>
<Input prefix={<LockOutlined style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="Password" />
)}
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" style={{marginRight: '10px'}}>
Login
</Button>
Or
<NavLink
style={{marginRight: '10px'}}
to='/signup/'> signup
</NavLink>
</FormItem>
</Form>
}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
loading: state.loading,
error: state.error
}
}
const mapDispatchToProps = dispatch => {
return {
onAuth: (username, password) => dispatch(actions.authLogin(username, password))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(NormalLoginForm);

Disable form.item 1 if form.item 2 is filled in

I want to hide form.item 1 if form.item 2 is filled in and the other way around.
I want to do it for the following code but i cant find the solution to this.
<Form.Item label="Url">
{getFieldDecorator('url')(<Input/>)}
</Form.Item>
<Form.Item label="Standaard Urls" >
{getFieldDecorator('url_id', {})(this.getSelectUrls())}
</Form.Item>
Basically i want too know how i can hide 1 form.item and the rest i can do myself
You need to use onFieldsChange of Form.create, that keeps your Form uncontrollable which is the cleanest way.
Wrap your Form with a state, pass it and use onFieldsChange like so:
const FormContainer = () => {
const [isVisible, setIsVisible] = useState(true);
const onFieldsChange = (_, changedFiels) => {
const { password } = changedFiels;
if (password) {
console.log(`Now changing ${password.name}`);
setIsVisible(false);
}
};
const ValidatedFields = Form.create({ onFieldsChange })(MyForm);
return <ValidatedFields isVisible={isVisible} />;
};
Warning: You need to figure how you want to "remove" the form field, it depends on if you need its state or not, for this you can use display CSS property:
// Will unmount the item and lose it state
{ isVisible && <Form.Item>...}
// Will keep the state and hide the item
<Form.Item style={{ display: isVisible ? 'auto' : 'none' }}>...
Full code:
In this example, you can write in the password field and it will hide other forms items:
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import { Input, Form, Icon } from 'antd';
import 'antd/dist/antd.css';
import './index.css';
const FormContainer = () => {
const [isVisible, setIsVisible] = useState(true);
const onFieldsChange = (_, changedFiels) => {
const { password } = changedFiels;
if (password) {
console.log(`Now changing ${password.name}`);
setIsVisible(false);
}
};
const ValidatedFields = Form.create({ onFieldsChange })(MyForm);
return <ValidatedFields isVisible={isVisible} />;
};
const MyForm = ({ form, isVisible }) => {
const { getFieldDecorator, validateFields } = form;
const handleSubmit = e => {
e.preventDefault();
validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
};
return (
<Form onSubmit={handleSubmit} className="login-form">
{isVisible && (
<Form.Item>
{getFieldDecorator('username', {
rules: [{ required: true, message: 'Please input your username!' }]
})(
<Input
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
placeholder="Item 1"
/>
)}
</Form.Item>
)}
<Form.Item style={{ display: isVisible ? 'auto' : 'none' }}>
{getFieldDecorator('username2', {
rules: [{ required: true, message: 'Please input your username!' }]
})(
<Input
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
placeholder="Item 2"
/>
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }]
})(
<Input
prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
type="password"
placeholder="Type here to hide other forms"
/>
)}
</Form.Item>
</Form>
);
};
ReactDOM.render(<FormContainer />, document.getElementById('root'));
const [showItem1, setShowItem1] = useState(true);
const [showItem2, setShowItem2] = useState(true);
onKeyPress = {() => {setShowItem1(true); setShowItem1(false); }}
onKeyPress = {() => {setShowItem1(false); setShowItem1(true); }}
{
showItem1 &&
<Form.Item label="Url">
{getFieldDecorator('url')(<Input/>)}
</Form.Item>
}
{
showItem2 &&
<Form.Item label="Standaard Urls" >
{getFieldDecorator('url_id', {})(this.getSelectUrls())}
</Form.Item>
}

Getting warning when i use withCookies()

I am using react-cookie in my project. When i use withCookies() i am getting warning in console log like this
Warning: Failed prop type: Invalid prop component of type object
supplied to Route, expected function
How can i solve this.?
Below is the code
import React from 'react';
import { Form, Icon, Input, Button, Checkbox } from 'antd';
import { withCookies } from "react-cookie";
import './Login.css';
class NormalLoginForm extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log(values);
const { cookies } = this.props;
cookies.set('token', 'dfsfsd54dg2g45fg575f432sd4');
}
});
}
render() {
const { getFieldDecorator } = this.props.form;
return (
<div style={{ textAlign: 'center' }}>
<img className="logo-white" src={'https://cdn.medcampus.io/wp-content/uploads/2018/08/01131559/MC_Logo_Black.png'} alt="logo"/>
<div className="login-container">
<br/>
<Form onSubmit={this.handleSubmit} className="login-form">
<Form.Item>
{getFieldDecorator('email', {
rules: [{ required: true, message: 'Please input your Email id!' }, {
type: 'email', message: 'The input is not valid E-mail!',
}],
})(
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Email" size={"large"} />
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
})(
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" size={"large"} placeholder="Password" />
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: true,
})(
<Checkbox>Remember me</Checkbox>
)}
<a className="login-form-forgot" href="">Forgot password</a>
<Button type="primary" size={"large"} htmlType="submit" className="login-form-button">Log in</Button>
</Form.Item>
</Form>
</div>
</div>
);
}
}
const Login = withCookies(Form.create({ name: 'normal_login' })(NormalLoginForm));
export { Login };
Following the comments, you are exporting all imports from your containers' files as default, so basically you'll get an object, not a function(the exact export).
To prevent this, there is several ways to do it:
Import your container in App from its own file.
in index.js of pages, you can do this :
import { Login } from `LoginContainerFile`;
import { Comp1} from `Comp1ContainerFile`;
import { Comp2} from `Comp2ContainerFile`;
export { Login, Comp1, Comp2 };
Good luck and hope it resolves your problem.

Getting Uncaught TypeError: Super expression must either be null or a function, not undefined

Below is my loginForm.js from where I suspect the error is originating:-
import { Form, Icon, Input, Button, Checkbox } from 'antd';
const FormItem = Form.Item;
import React, { Component } from 'react';
class NormalLoginForm extends Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
}
render() {
const { getFieldDecorator } = this.props.form;
return (
<Form onSubmit={this.handleSubmit} className="login-form">
<FormItem>
{getFieldDecorator('userName', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
})(
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="Password" />
)}
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="login-form-button">
Log in
</Button>
Or register now!
</FormItem>
</Form>
);
}
}
const WrappedNormalLoginForm = Form.create()(NormalLoginForm);
export default WrappedNormalLoginForm;
Below is my main component file where I load handle routing:-
import React, { Component } from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import WrappedNormalLoginForm from './loginForm'
export default class App extends Component {
render() {
return (
<div className="container">
<BrowserRouter>
<div>
<Route exact path="/" component={WrappedNormalLoginForm} />
</div>
</BrowserRouter>
</div>
);
}
}
I am unable to resolve this issue. I have extended using capital C which was mentioned as a fix for many of the questions asked regarding this.

Resources