eslint hoist never doesn't work in my react js app - reactjs

I am having a painful moment because of some small issue in my react app.
import React, { useState } from 'react';
import { Box } from '#material-ui/core';
import { connect } from 'react-redux';
import { PropTypes } from 'prop-types';
import { HeadTwo, Text, StdLink } from '../../styled-components/Text';
import { ContainedBtn } from '../../styled-components/Button';
import { TextField } from '../../styled-components/Input';
import { FlexCenter, FlexStart, Form } from '../../styled-components/Layout';
import { login } from '../../redux/auth/actions';
const SignIn = ({ login, history }) => {
const [form, setForm] = useState({
email: '',
password: '',
});
const handleChange = e => {
setForm({
...form,
[e.target.name]: e.target.value,
});
};
const handleSubmit = e => {
e.preventDefault();
login(form, history);
};
return (
<FlexCenter>
<Form onSubmit={e => handleSubmit(e)} width="45rem" mt="20px" mb="20px">
<FlexStart mb={2} borderBottom={2} borderColor="common.dark">
<HeadTwo sz="2.6rem">Sign In</HeadTwo>
</FlexStart>
<TextField mb={2} hidelabel={form.email.length > 0 ? 'none' : null}>
<input
onChange={handleChange}
value={form.email}
type="email"
name="email"
placeholder="email"
id="email"
/>
</TextField>
<TextField mb={2} hidelabel={form.password.length > 0 ? 'none' : null}>
<input
onChange={handleChange}
value={form.password}
type="password"
placeholder="password"
name="password"
id="password"
/>
</TextField>
<Box mb={1}>
<ContainedBtn bg="#000" cr="#fff">
LOGIN
</ContainedBtn>
</Box>
<FlexCenter mb={1}>
<Text> Don't have an account? </Text>
<Box ml={1}>
<StdLink to="/register">register</StdLink>
</Box>
</FlexCenter>
<FlexCenter mb={1}>
<Text> Forget your password?</Text>
<Box ml={1}>
<StdLink>recover</StdLink>
</Box>
</FlexCenter>
</Form>
</FlexCenter>
);
};
SignIn.propTypes = {
login: PropTypes.func.isRequired,
history: PropTypes.object.isRequired,
};
export default connect(
null,
{ login }
)(SignIn);
so this is my signIn component and login function is yelling at me saying 'login is already declared in upper scope', which is quite weird because login prop comes from connect fn right?
anyway, So I tried changing eslint rule like this
{
"rules": {
"no-shadow": [
"error",
{ "builtinGlobals": false, "hoist": "never", "allow": [] }
]
}
}
since I set hoist to never, the warning should be gone, but it still remained.
does anyone know what I did wrong?
thanks !!

The login function that is imported will not work since you have parameter with the same name. You just need to rename:
const SignIn = ({ login: signin, history }) => {
// now the imported login will work
// to use login parameter, you now have signin

Related

how to do testing in react redux application using Jest enzyme?

Login.test.js:-
import { shallow, mount } from "enzyme";
import renderer from "react-test-renderer";
import Login from "../Login";
import { Provider } from "react-redux";
//import LoginReducer from "../../../redux/reducers/loginReducer";
import configureStore from "redux-mock-store";
const mockStore = configureStore([]);
describe("Login Component", () => {
let store;
let jsx;
beforeEach(() => {
store = mockStore({ login: { email: "", password: "" } });
jsx = (
<Provider store={store}>
<Login />
</Provider>
);
});
it("should render an email input tag", () => {
const wrapper = shallow(jsx);
expect(wrapper.find("Field[type='email']").exists()).toBe(true);
});
it("should render a password input tag", () => {
const wrapper = shallow(jsx);
expect(wrapper.find('Field[type="password"]').exists()).toBe(true);
});
it("should render a submit button", () => {
const wrapper = shallow(jsx);
expect(wrapper.find('button[type="submit"]').exists()).toBe(true);
});
});
Appstore:-
/** combine reducers*/
let rootReducer = combineReducers({
register: RegisterReducer,
login: LoginReducer
Login.js:-
import { React, useState, useEffect, useContext } from "react";
import { useHistory } from "react-router";
import "./common_style.css";
import { connect } from "react-redux";
import * as actionCreator from "../../redux/actions/userActionCreater";
import "../common/common_style.css";
import {
Grid,
Paper,
Avatar,
TextField,
Button,
Typography,
Link,
} from "#material-ui/core";
import LockOutlinedIcon from "#material-ui/icons/LockOutlined";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import Checkbox from "#material-ui/core/Checkbox";
import InputAdornment from "#material-ui/core/InputAdornment";
import AccountCircle from "#material-ui/icons/AccountCircle";
import LockIcon from "#material-ui/icons/Lock";
import { Formik, Form, Field, ErrorMessage } from "formik";
import * as Yup from "yup";
//import { propTypes } from "react-bootstrap/esm/Image";
import InitializeReduxState from "./InitializeReduxState";
const paperStyle = {
padding: 20,
height: "70vh",
width: 280,
margin: "60px auto",
marginTop: "110px",
};
const avatarStyle = { backgroundColor: "#1bbd7e" };
const btnstyle = { margin: "8px 0" };
const Login = (props) => {
const initialValues = {
email: "",
password: "",
};
const validationSchema = Yup.object().shape({
email: Yup.string().email("Please enter valid email").required("Required"),
password: Yup.string("Enter your password")
.required("Required")
.min(4, "Password should be of minimum 4 characters length"),
});
const onSubmit = (values) => {
const payload = { email: values.email, password: values.password };
props.login(payload);
};
let history = useHistory();
useEffect(() => {
if (props.isLoggedIn === true) {
props.flashNotification({
message: "Login Succeessful...",
type: "success",
});
if (props.role === "admin") {
history.push("/admin");
} else if (props.role === "patient") {
patientStatus();
} else {
history.push("/physician");
}
}
}, []);
const patientStatus = () => {
if (props.currentUser.isActive) {
history.push("/demographics");
} else {
history.push("/patientinactive");
}
};
return (
<>
<Grid>
<Paper elevation={10} style={paperStyle}>
<Grid align="center">
<Avatar style={avatarStyle}>
<LockOutlinedIcon />
</Avatar>
<br />
<h4>Sign In</h4>
</Grid>
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}
>
{(props) => (
<Form>
<Field
as={TextField}
label="Email"
margin="normal"
type="text"
name="email"
// onChange={handleUserChange}
placeholder="Enter email"
fullWidth
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AccountCircle />
</InputAdornment>
),
}}
variant="standard"
helperText={<ErrorMessage name="email" />}
/>
<Field
as={TextField}
label="password"
placeholder="Enter password"
type="password"
name="password"
// onChange={handleUserChange}
fullWidth
InputProps={{
startAdornment: (
<InputAdornment position="start">
<LockIcon />
</InputAdornment>
),
}}
helperText={<ErrorMessage name="password" />}
/>
<Button
type="submit"
color="primary"
variant="contained"
style={btnstyle}
fullWidth
>
Sign in
</Button>
</Form>
)}
</Formik>
<Typography> Do you have an account ?</Typography>
Sign Up
<p className="text text-danger fw-bold text-center">
{props.globalmessage}!!!
</p>
</Paper>
</Grid>
<InitializeReduxState />
</>
);
};
const mapStatetoProps = (state) => {
return {
isLoggedIn: state.login.isLoggedIn,
role: state.login.role,
globalmessage: state.login.globalmessage,
authToken: state.login.authToken,
currentUser: state.login.loggedUserInfo,
};
};
const mapDispatchToProps = (dispatch) => {
return {
login: (user) => dispatch(actionCreator.Login(user)),
};
};
let hof = connect(mapStatetoProps, mapDispatchToProps);
export default hof(Login);
Here I have tested my Login component with some simple test cases and I have also mock my store because my application is using Redux but it is giving me error like
expect(received).toBe(expected) // Object.is equality
Expected: true
Received: false
I have a doubt that in beforeeach I have used the email and password. Is it correct? Is there is something that I have done wrong?

How to set ref of a Form Item inside a 'antd' Form in ReactJS?

With similar approach able to get the desired refs in Form.Control when I am using react-bootstrap Form
But not getting the refs when using antd forms in ReactJS
<Form.Item>
<Input placeholder='Name' size='large' ref="usernameref" />
</Form.Item>
not able to access this ref in other place like on button click of the button inside the form
The entire code below
import React from "react";
//import { Modal, Form ,Button } from "react-bootstrap";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import { addUser, updateUser, loadoff, loadon} from "../actions/action.js";
import { Button, Form, Modal ,Input } from "antd";
class UserModalWindow extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
update: this.props.update,
rowindex: this.props.rowindextoupdate
};
}
static getDerivedStateFromProps(props, state) {
return { rowindex: props.rowindextoupdate };
}
render() {
async function wait(duration = 2000) {
await new Promise(resolve => setTimeout(resolve, duration));
}
const layout = {
labelCol: { span: 24 },
wrapperCol: { span: 24 },
};
return (
<Modal {...this.props} title="User Form" >
<Form
{...this.props}
{...this.layout}
name="basic"
>
<Form.Item
label='Name'
name='name'
rules={[{ required: true, message: 'Please input your name' }]}>
<Input placeholder='Name' size='large' ref="usernameref" />
</Form.Item>
<Form.Item
label='Email'
name='email'
rules={[
{
type: 'email',
message: 'The input is not valid mail.',
},
{
required: true,
message: 'Please input your mail id',
},
]}>
<Input placeholder='Email' size='large' ref="usermailref"/>
</Form.Item>
<Button loading={this.props.loader.loading} onClick = {async()=>
{
var obj = {}
obj.field1 = this.refs.usernameref.value ; // here both the refs are undefined
obj.field2 = this.refs.usermailref.value;
console.log(this.refs)
this.props.loadon();
await wait();
this.props.loadoff();
if(this.state.update === 'true')
{
obj.index = this.state.rowindex.index ;
this.props.updateUser(obj);
}
else
{
console.log(obj)
this.props.addUser(obj);
}
this.props.onHide();
}}
> Save</Button>
</Form>
</Modal>
);
}
}
function mapStateToProps(state) {
return {
loader: state.loader
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ addUser, updateUser, loadon, loadoff }, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(UserModalWindow);
But using React-bootstrap Forms works as desired
What might be the reason? Do I need to use DecoratorField?
You should give ref to Form tag
please follow these instructions
1)create ref like this
formRef = React.createRef();
2)use this ref in the form tag like this
<Form ref={this.formRef} name="control-ref">code goes here.........</Form>
Than you can use this ref,you can also check antd documentation how it will work https://ant.design/components/form/
please reply to this thread if you are facing the issue or find it helpfull

Problem with a Mutation from Apollo-Client

I am trying to perform a Login with JSON web tokens. Right now I am doing a simple thing, I just want to give a username and a password and, if they are correct ,as a response I want a console log with the token.
Instead of receiving a token in the console, all I get is the http-address changing from http:/localhost:3000/login to http:/localhost:3000/login?username=username&password=password
Can somebody explain me why does that happen?
Here is my code:
import React, {useState} from 'react';
import {gql} from 'graphql-tag';
import {Mutation} from 'react-apollo';
import {Button, TextField} from '#material-ui/core';
const LOGIN = gql`
mutation Login($username: String!, $password:String!){
login(username:$username, password:$password){
token
}
}
`;
export default function Login(){
const [formState, setFormState] = useState({
values:{}
})
};
const handleChange = event => {
event.persist();
setFormState( formState => ({
...formState,
values:{
...formState.values,
[event.target.name]:event.target.value
}
}));
};
const handleSubmit = async(event, login)=>{
event.preventDefault();
console.log(formState.values)
login().then(async({data}) => {
localStorage.setItem('token', data.login.token);
})
.catch(function(e){
console.log('Something went wrong');
});
console.log(localStorage.getItem('token'));
}
return (
<Mutation mutation={LOGIN} variables={{username:formState.values.username, password: formState.values.password }}>
{(login, {data}) => (
<div>
<form className="form" onSubmit={handleSubmit, login}>
<TextField
label="Username"
name="username"
onChange={handleChange}
value=formState.values.username
></TextField>
<TextField
label="Password"
name="password"
onChange={handleChange}
value=formState.values.password
></TextField>
<Button type="submit">Login</Button>
</form>
</div>
)}</Mutation>
);
I would like to know where my error is, I am new to React and Javascript

react no-shadow rule handling

I am pretty new in react. I am trying to create first app which should handle login. Actually everything works even now, but im getting eslint error with no-shadow on line 18.
This is my LoginForm controller:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Button, TextInput, Logo, Block } from 'vcc-ui';
import { login } from '../../redux/reducer';
import { styles } from './LoginForm-styles';
class LoginForm extends Component {
constructor(props) {
super(props);
this.state = {};
}
onSubmit = (e) => {
e.preventDefault();
const { username, password } = this.state;
login(username, password);
}
render() {
const {username, password} = this.state;
const {isLoginPending, isLoginSuccess, loginError} = this.props;
return (
<Block
extend={styles.loginWrapper}
>
<Block
extend={styles.loginForm}
>
<Block
as="form"
name="loginForm"
onSubmit={this.onSubmit}
>
<Block
extend={styles.loginLogo}
>
<Logo height="60"/>
</Block>
<Block
extend={styles.loginInput}
>
<TextInput
value={username}
placeholder="username"
type="text" name="username"
onChange={e => this.setState({username: e.target.value})}
/>
</Block>
<Block
extend={styles.loginInput}
>
<TextInput
value={password}
placeholder="password"
type="password"
name="password"
onChange={e => this.setState({password: e.target.value})}
/>
</Block>
<Block
extend={styles.loginButton}
>
<Button
loading={isLoginPending}
variant="outline"
type="submit"
fullWidth={["s","m","l"]}
>
Login
</Button>
</Block>
{isLoginPending && <div>Processing</div>}
{isLoginSuccess && <div>Logged In</div>}
{loginError && <div>Incorrect Username or Password</div>}
</Block>
</Block>
</Block>
)
}
}
LoginForm.propTypes = {
isLoginPending: PropTypes.bool,
isLoginSuccess: PropTypes.bool,
loginError: PropTypes.string,
login: PropTypes.func
};
LoginForm.defaultProps = {
isLoginPending: false,
isLoginSuccess: false,
loginError: "",
login: () => undefined
};
const mapStateToProps = (state) => ({
isLoginPending: state.isLoginPending,
isLoginSuccess: state.isLoginSuccess,
loginError: state.loginError,
})
const mapDispatchToProps = (dispatch) => ({
login: (username, password) => dispatch(login(username,password))
})
export default connect(mapStateToProps, mapDispatchToProps)(LoginForm)
onSubmit function is throwing no-shadow esling error. Please how can i rewrite it or define login prop so it will not throw it?
I know that login is somehow changing its value on 2 places, but i dont know how to make it more "nice" lets say.
Do anybody have some idea?
Thanks.
you can import your login with an alias:
import { login as reducerLogin } from '../../redux/reducer';
...
const mapDispatchToProps = (dispatch) => ({
login: (username, password) => dispatch(reducerLogin(username,password))
})
This error occurs when you have two variables with the same name but different scope.
By the way, I believe you should be using this.props.login(username, password); instead of calling the imported action creator directly.
You could give the mapped function whatever name you like. For instance:
// At line 18
this.props.loginAction(username, password)
// Mapping action creator shortcut...
export default connect(mapStateToProps,{ loginAction: login })(LoginForm)

React Component not updating after adding new value in store

So I am using react, redux and firebase for this small crud app, whenever a new employee is created I redirect to the home component which should display all the employees created including the new one. But the new employee isn't showing up after redirection from create employee. What seems to be the issue, essentially I want is for the Home component to update with the new data.
Home.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import EmployeesList from '../employees/EmployeesList'
import { firestoreConnect } from 'react-redux-firebase'
import { compose } from 'redux'
class Home extends Component {
render() {
const { employees } = this.props
return (
<div>
<EmployeesList employees={employees} />
</div>
)
}
}
const mapStateToProps = (state) => {
// console.log(state)
return ({
employees: state.firestore.ordered.employees
})
}
export default compose(
connect(mapStateToProps),
firestoreConnect([
{ collection: 'employees', orderBy: ['createdAt', 'desc'] }
])
)(Home)
CreateEmployee.js
import React, { Component } from 'react'
import { compose } from 'redux'
import { connect } from 'react-redux'
import { withRouter } from "react-router";
import { createEmployee } from '../../store/actions/employeeActions'
import { withStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import TextField from '#material-ui/core/TextField';
import Typography from '#material-ui/core/Typography';
const styles = theme => ({
bt_create: {
margin: theme.spacing.unit,
padding: '10'
},
input: {
display: 'none',
},
});
class CreateEmployee extends Component {
state = {
name: '',
email: '',
department: '',
salary: ''
}
handleChange = e => {
this.setState({
[e.target.id]: e.target.value
})
}
handleSubmit = e => {
e.preventDefault()
// console.log(this.state)
// TODO store state data in db
this.props.createEmployee(this.state)
this.props.history.push({
pathname: '/'
})
}
render() {
return (
<div>
<br />
<Typography variant="h6" color="inherit">
Create new employee
</Typography>
<form onSubmit={this.handleSubmit}>
<TextField
id="name"
label="Name"
defaultValue=""
margin="normal"
onChange={this.handleChange}
/>
<br />
<TextField
id="email"
label="Email"
defaultValue=""
margin="normal"
onChange={this.handleChange}
/>
<br />
<TextField
id="department"
label="Department"
defaultValue=""
margin="normal"
onChange={this.handleChange}
/>
<br />
<TextField
id="salary"
label="Salary"
defaultValue=""
margin="normal"
onChange={this.handleChange}
/>
<br />
<br />
<Button type="submit" variant="contained" color="primary" className="bt_create">Create</Button>
</form>
</div>
)
}
}
const mapDispatchToProps = dispatch => {
return {
createEmployee: (employee) => dispatch(createEmployee(employee))
}
}
export default compose(
withStyles(styles),
withRouter,
connect(null, mapDispatchToProps)
)(CreateEmployee)
Create employee action
export const createEmployee = employee => {
return (dispatch, getState, { getFirebase, getFirestore }) => {
const firestore = getFirestore()
// TODO add employee here
firestore.collection('employees').add({
...employee,
createdAt: new Date(),
updatedAt: new Date()
}).then(() => {
dispatch({
type: 'CREATE_EMPLOYEE_SUCCESS',
employee: employee
})
}).catch((err) => {
dispatch({ type: 'CREATE_EMPLOYEE_ERROR', err })
})
}

Resources