it seems that i am unable to get the form to rerender on each keystroke. I must be doing something wrong I just cannot tell what it is. The GetStartedForm function never runs twice, and neither does the function that contains the Field input.
use of redux form
const GetStartedForm = (props) => {
const {
handleSubmit,
pristine
} = props;
return (
<Form onSubmit={handleSubmit}>
<Field
name="email"
component={FormField}
type="text"
size="xl"
placeholder="Email Address"
autoComplete="email"
validate={[required(), email()]}
/>
<Button
disabled={pristine}>Get Started</Button>
</Form>
);
}
export default reduxForm({ form: 'getstarted' })(GetStartedForm);
implementation
<GetStarted onSubmit={e => {
console.log(e);
}} />
input field
const TextField = props => {
const { input, meta, size } = props;
console.log(props);
const properties = meta.uncontrolled ? {
defaultValue: props.defaultValue
} : {
value: input.value
};
return (
<React.Fragment>
{props.label && (
<label htmlFor={input.name} className="form__label">
{props.label}
{props.required ? ' *' : null}
</label>
)}
<Input
type={props.type ? props.type : 'text'}
className={props.className}
name={input.name}
id={input.name}
size={props.size}
readOnly={props.readOnly}
onChange={input.onChange}
autoFocus={props.autoFocus}
autoComplete={props.autoComplete}
placeholder={props.placeholder}
{...properties}
/>
{meta.touched && meta.error ? (
<div className="form__field-error">{meta.error}</div>
) : null}
</React.Fragment>
);
};
when i pass in uncontrolled like this i am able to get the text to at least show up on my screen, but i seem to be unable to get the form function to run again, which means that my button is stuck at disabled (pristine)
<Field
name="email"
component={FormField}
type="text"
size="xl"
placeholder="Email Address"
autoComplete="email"
validate={[required(), email()]}
meta={{uncontrolled: true}}
/>
yes reducers are set up
/**
* Combine all reducers in this file and export the combined reducers.
*/
import { fromJS } from 'immutable';
import { combineReducers } from 'redux-immutable';
import { LOCATION_CHANGE } from 'react-router-redux';
import { reducer as formReducer } from 'redux-form';
import {
LOGOUT_USER_REQUEST
} from 'constants'
import globalReducer from 'containers/App/reducer';
import languageProviderReducer from 'containers/LanguageProvider/reducer';
/*
* routeReducer
*
* The reducer merges route location changes into our immutable state.
* The change is necessitated by moving to react-router-redux#5
*
*/
// Initial routing state
const routeInitialState = fromJS({
location: null,
});
/**
* Merge route into the global application state
*/
function routeReducer(state = routeInitialState, action) {
switch (action.type) {
/* istanbul ignore next */
case LOCATION_CHANGE:
return state.merge({
location: action.payload,
});
default:
return state;
}
}
/**
* Creates the main reducer with the dynamically injected ones
*/
export default function createReducer(injectedReducers) {
const composite = combineReducers({
route: routeReducer,
global: globalReducer,
language: languageProviderReducer,
form: formReducer,
...injectedReducers,
});
return rootReducer;
function rootReducer(state_, action) {
let state = state_;
if (action.type === LOGOUT_USER_REQUEST) {
state = null;
}
return composite(state, action);
}
}
I just realized that this react boilerplate uses immutable as its base so i had to import redux-form/immutable everywhere i was using redux-form
Related
When I try to type in the boxes on the webpage it doesn't register that I am typing anything. I am guessing it has something to do with the handleChange or onChange, but I could use some help here. I am still pretty new to React and trying to figure it out. What am I missing here?
import React, {Component} from 'react';
import { Form } from 'semantic-ui-react';
class Assessments extends Component {
state = {assessment_name: '', assessment_type: ''}
componentDidMount() {
if (this.props.id) {
const { assessment_name, assessment_type } = this.props
this.setState({ assessment_name, assessment_type })
}
}
handleChange = (a) => {
const { name, value } = a.target
this.setState({ [name]: value })
}
handleSubmit = (a) => {
a.preventDefault()
if (this.props.id) {
const { id, history } = this.props
this.props.updateName(id, this.state, history)
this.props.toggleUpdate()
}
this.props.close()
this.setState({ assessment_name: '', assessment_type: ''})
}
close = () => this.setState({ open: false })
render() {
const { assessment_name, assessment_type } = this.state
return(
<Form onSubmit={this.handleSubmit}>
<Form.Input
name=''
value={assessment_name}
onChange={this.handleChange}
label='Assessment Name'
required
/>
<Form.Input
name='AssessmentType'
value={assessment_type}
onChange={this.handleChange}
label='Assessment Type'
required
/>
<Form.Button>Submit</Form.Button>
</Form>
)
}
}
export default Assessments;
You're not passing the right names to the Form.Input components which the handleChange function uses to update the state. They have to be 'assessment_name' and 'assessment_type' respectively to make sure the state gets updated on input change events and the new values get reflected on the fields.
<>
<Form.Input
name="assessment_name"
value={assessment_name}
onChange={this.handleChange}
label="Assessment Name"
required
/>
<Form.Input
name="assessment_type"
value={assessment_type}
onChange={this.handleChange}
label="Assessment Type"
required
/>
</>
So I have built a Wizard Form using React-Final-Form that I am using in my sign-up page. I am trying to figure out how I can display all user inputs on the final page as a way for the user to double-check/verify their inputs before submitting. Any help would be greatly appreciated!
(P.S. - I tried researching this before posting, but all I was able to find was storing user inputs in Redux and accessing them from there, which I'd like to avoid, if at all possible.)
Here is an example link that shows what I want to do - Please feel free to fork and play around with it if you are trying to figure out a solution! https://codesandbox.io/s/0332k02x0v
Here is the code, shortened to include only the relevant bits:
My Wizard.js page:
import React, { Component } from "react";
import PropTypes from "prop-types";
import { Form } from "react-final-form";
class Wizard extends Component {
static propTypes = {
onSubmit: PropTypes.func.isRequired
};
static Page = ({ children }) => children;
constructor(props) {
super(props);
this.state = {
page: 0,
values: props.initialValues || {}
};
}
next = values =>
this.setState(state => ({
page: Math.min(state.page + 1, this.props.children.length - 1),
values
}));
previous = () =>
this.setState(state => ({
page: Math.max(state.page - 1, 0)
}));
validate = values => {
const activePage = React.Children.toArray(this.props.children)[
this.state.page
];
return activePage.props.validate ? activePage.props.validate(values) : {};
};
handleSubmit = values => {
const { children, onSubmit } = this.props;
const { page } = this.state;
const isLastPage = page === React.Children.count(children) - 1;
if (isLastPage) {
return onSubmit(values);
} else {
this.next(values);
}
};
render() {
const { children } = this.props;
const { page, values } = this.state;
const activePage = React.Children.toArray(children)[page];
const isLastPage = page === React.Children.count(children) - 1;
return (
<Form
initialValues={values}
validate={this.validate}
onSubmit={this.handleSubmit}
>
{({ handleSubmit, submitting, values }) => (
<form onSubmit={handleSubmit}>
{activePage}
<div className="buttons">
{page > 0 && (
<button type="button" onClick={this.previous}>
« Previous
</button>
)}
{!isLastPage && <button type="submit">Next »</button>}
{isLastPage && (
<button type="submit" disabled={submitting}>
Submit
</button>
)}
</div>
{/* <pre>{JSON.stringify(values, 0, 2)}</pre> */}
</form>
)}
</Form>
);
}
}
export default Wizard;
My index.js page:
import React, { Component } from "react";
import { Field } from "react-final-form";
import formatString from "format-string-by-pattern";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import Wizard from "./Wizard";
import Styles from "./Styles";
import { addUser } from "../../../actions/authActions";
class ReactFinalForm2 extends Component {
state = {};
render() {
const onSubmit = async values => {
this.props.addUser(values);
// API query here
};
const Error = ({ name }) => (
// Error handing here
);
return (
<Styles>
<div>
<Wizard initialValues={{}} onSubmit={onSubmit}>
<Wizard.Page
validate={values => {
// Page validation here
}}
>
// Page inputs here
</Wizard.Page>
<Wizard.Page
validate={values => {
// Page validation here
}}
>
// Page inputs here
</Wizard.Page>
<Wizard.Page
validate={values => {
// Page validation here
}}
>
// Page inputs here
</Wizard.Page>
<Wizard.Page>
{/* *** THIS IS WHERE I WOULD LIKE TO DISPLAY ALL PREVIOUS VALUES (SO THE USER CAN CONFIRM / DOUBLE-CHECK THEIR INPUTS BEFORE SUBMITTING) *** */}
</Wizard.Page>
</Wizard>
</div>
</Styles>
);
}
}
ReactFinalForm2.propTypes = {
addUser: PropTypes.func.isRequired
};
export default connect(
null,
{ addUser }
)(ReactFinalForm2);
I have added a state to the parent component. Changing this state on every submit from the child. I have JSON stringify the state in parent component. As you said no need to use redux, this is the workaround I came with. Still your code has a potential for improvements. Please check this working sandbox:
[ https://codesandbox.io/s/zrvloq4o6x ]
Wizard.js change
handleSubmit = values => {
const { children, onSubmit } = this.props;
const { page } = this.state;
const isLastPage = page === React.Children.count(children) - 1;
if (isLastPage) {
return onSubmit(values);
} else {
this.next(values);
}
// Change added
this.props.onStateChange(values);
};
Index.js
import React from "react";
import { render } from "react-dom";
import Styles from "./Styles";
import { Field } from "react-final-form";
import Wizard from "./Wizard";
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const onSubmit = async values => {
await sleep(300);
window.alert(JSON.stringify(values, 0, 2));
};
const Error = ({ name }) => (
<Field
name={name}
subscribe={{ touched: true, error: true }}
render={({ meta: { touched, error } }) =>
touched && error ? <span>{error}</span> : null
}
/>
);
const required = value => (value ? undefined : "Required");
let data = {};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.onStateChange = this.onStateChange.bind(this);
}
onStateChange = values => {
this.setState({ data: values });
console.log(values);
};
render() {
return (
<Styles>
<h1>🏁 React Final Form Example</h1>
<h2>Wizard Form</h2>
<a href="https://github.com/erikras/react-final-form#-react-final-form">
Read Docs
</a>
<p>
Notice the mixture of field-level and record-level (or{" "}
<em>page-level</em> in this case) validation.
</p>
<Wizard
initialValues={{}}
onStateChange={this.onStateChange}
onSubmit={onSubmit}
>
<Wizard.Page>
<div>
<label>First Name</label>
<Field
name="firstName"
component="input"
type="text"
placeholder="First Name"
validate={required}
/>
<Error name="firstName" />
</div>
<div>
<label>Last Name</label>
<Field
name="lastName"
component="input"
type="text"
placeholder="Last Name"
validate={required}
/>
<Error name="lastName" />
</div>
</Wizard.Page>
<Wizard.Page
validate={values => {
const errors = {};
if (!values.notes) {
errors.notes = "Required";
}
return errors;
}}
>
<div>
<label>Best Stooge?</label>
<div>
<label>
<Field
name="stooge"
component="input"
type="radio"
value="larry"
/>{" "}
Larry
</label>
<label>
<Field
name="stooge"
component="input"
type="radio"
value="moe"
/>{" "}
Moe
</label>
<label>
<Field
name="stooge"
component="input"
type="radio"
value="curly"
/>{" "}
Curly
</label>
</div>
</div>
<div>
<label>Notes</label>
<Field name="notes" component="textarea" placeholder="Notes" />
<Error name="notes" />
</div>
</Wizard.Page>
<Wizard.Page>
<div>
<p>
<b>Display all previous values here for user verification </b>
<br />
<i>{JSON.stringify(this.state.data, 0, 2)}</i>
</p>
</div>
</Wizard.Page>
</Wizard>
</Styles>
);
}
}
render(<App />, document.getElementById("root"));
I want to pass initial values (coming from the props of a react-redux component) to my redux-form. But, I get not value when I inspect the data passed to the renderField . I followed the posts here in SO and on redux-form git forum, and I'm using initialValues in mapStateToProps but still it doesn't work.
This is my react-redux component which holds the redux-form:
class ShowGroup extends Component {
render() {
if (this.state.loading) {
return <div>Loading group ....</div>;
}
if (this.state.error) {
return <div>{this.state.error}</div>;
}
let group = this.props.groups[this.groupId];
return (
<div className="show-group">
<form>
<Field
name="name"
fieldType="input"
type="text"
component={renderField}
label="Name"
validate={validateName}
/>
</form>
</div>
);
}
}
function mapStateToProps(state) {
return {
groups: state.groups,
initialValues: {
name: 'hello'
}
};
}
const mapDispatchToProps = (dispatch) => {
return {
//.....
};
};
export default reduxForm({
form:'ShowGroup'
})(
connect(mapStateToProps, mapDispatchToProps)(ShowGroup)
);
This is my renderField code:
export const renderField = function({ input, fieldType, label, type, meta: { touched, error }}) {
let FieldType = fieldType;
return (
<div>
<label>{label}</label>
<div>
<FieldType {...input} type={type} />
{touched && error && <span>{error}</span>}
</div>
</div>
);
}
You are exporting the wrapped component with incorrect order
export default reduxForm({
form:'ShowGroup'
})(
connect(mapStateToProps, mapDispatchToProps)(ShowGroup)
);
should be
export default connect(mapStateToProps, mapDispatchToProps)(reduxForm({
form:'ShowGroup'
})(ShowGroup);
The reason being that the redux form HOC needs the initialValues prop for itself, if you reverse the order, reduxForm doesn't get the props rather they are passed directly to the component, which doesn't know what to do with it.
Novice.
I have a redux form component called Client. There is a sub component in that form called Address. Address is called in client as follows:
<FormSection name="Address">
<Address />
</FormSection>
Address is in the form of AddressContainer and Address.
I am setting initial values for the Client redux form as follows:
let ClientForm = reduxForm({
form: CLIENT_FORM_NAME
})(Client);
let ClientForm2 = connect(
(state, ownProps) => ({
initialValues: ownProps.isEditMode ? state.editClient : {}, // pull initial values from client reducer
enableReinitialize: true
}),
{ reducer } // bind client loading action creator
)(ClientForm);
export default ClientForm2;
However the Address component does not get any of the initial state set in it.
How do you, in redux form, pass the initial state down from the main form to the its sub components - in this case Address?
AddressContainer:
import React, { Component, PropTypes } from "react";
import { connect } from "react-redux";
import { Field, change } from "redux-form";
import { Col, Panel, Row } from "react-bootstrap";
import Select from "react-select";
import Address from "./address";
import { getSuburbs, ensureStateData } from "./actions";
import FormField from "../formComponents/formField";
import TextField from "../formComponents/textField";
import StaticText from "../formComponents/staticText";
import { CLIENT_FORM_NAME } from "../clients/client/client";
export class AddressContainer extends Component {
static contextTypes = {
_reduxForm: PropTypes.object.isRequired
};
constructor(props, context) {
super(props, context);
this.state = {
selectedSuburb: null
};
}
// Manage Select.Async for new data request - for suburbs.
handleSuburbSearch = query => {
const { addressData } = this.props;
const companyStateId = addressData.companyStateId;
if (!query || query.trim().length < 2) {
return Promise.resolve({ options: [] });
}
const queryString = {
query: query,
companyStateId: companyStateId
};
return getSuburbs(queryString).then(data => {
return { options: data };
});
};
// Update the current state with the selected suburb.
onSuburbStateChange = value => {
this.setState({ selectedSuburb: value });
};
componentDidMount() {
this.props.ensureStateData();
}
render() {
const { initialValues, addressData, updatePostcodeValue } = this.props;
const { value } = this.state;
const sectionPrefix = this.context._reduxForm.sectionPrefix;
if (addressData.isLoading || !addressData.states.length) {
return <p>Loading</p>;
}
if (addressData.error) {
return <p>Error loading data</p>;
}
console.group("InitalValues Address");
const companyStateId = addressData.companyStateId;
console.log("companyStateId:", companyStateId);
initialValues.Address = {
...initialValues.Address,
state: addressData.states.find(
option => option.stateId === companyStateId
)
};
console.log(
"addressData.states.Find: ",
addressData.states.find(option => option.stateId === companyStateId)
);
console.log("addressData.states: ", initialValues.Address.state);
console.log("initialValues.Address: ", initialValues.Address);
console.log("initialValues: ", initialValues);
console.groupEnd();
return (
<Address
initialValues={initialValues}
handleSuburbSearch={this.handleSuburbSearch}
onSuburbStateChange={this.onSuburbStateChange}
updatePostcodeValue={updatePostcodeValue}
addressData={addressData}
sectionPrefix={sectionPrefix}
/>
);
}
}
const mapStateToProps = state => ({
initialValues: state.editClient,
companyStateId: state.companyStateId,
addressData: state.addressData
});
const mapDispatchToProps = dispatch => ({
ensureStateData: () => dispatch(ensureStateData()),
getSuburbs: values => dispatch(getSuburbs(values)),
updatePostcodeValue: (postcode, sectionPrefix) =>
dispatch(
change(
CLIENT_FORM_NAME,
`${sectionPrefix ? sectionPrefix + "." : ""}postcode`,
postcode
)
)
});
export default connect(mapStateToProps, mapDispatchToProps)(AddressContainer);
Address:
import React, { Component, PropTypes } from "react";
import { connect } from "react-redux";
import { Field, change, reduxForm } from "redux-form";
import { Col, Panel, Row } from "react-bootstrap";
import Select from "react-select";
import { getSuburbs } from "./actions";
import FormField from "../formComponents/formField";
import TextField from "../formComponents/textField";
import StaticText from "../formComponents/staticText";
import reducer from "../address/reducer";
export const Address = props => {
const {
initialValues,
handleSuburbSearch,
companyValue,
onSuburbStateChange,
updatePostcodeValue,
addressData,
sectionPrefix
} = props;
const { reset } = props;
{
console.log("PROPS ADDRESS DATA: ", props.stateData);
console.log("PROPS INITIALVALIES: ", props.initialValues);
console.log("COMPANY VALUE: ", companyValue);
}
return (
<Panel header={<h3>Client - Address Details</h3>}>
<Row>
<Field
component={TextField}
name="address1"
id="address1"
type="text"
label="Address Line 1"
placeholder="Enter street 1st line..."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
<Field
component={TextField}
name="address2"
id="address2"
type="text"
label="Address Line 2"
placeholder="Enter street 2nd line..."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
</Row>
<Row>
<Field
component={props => {
const { input, id, placeholder, type } = props;
const {
fieldCols,
labelCols,
controlCols,
label,
inputClass
} = props;
// The props we want the inner Select textbox to have.
const { name, onChange } = input;
const onStateChange = state => {
console.log("onStateChange", state);
onChange(state);
};
return (
<FormField
id={id}
label={label}
fieldCols={fieldCols}
labelCols={labelCols}
controlCols={controlCols}
inputClass={inputClass}
>
<Select
name={name}
onChange={onStateChange}
placeholder="Select state"
valueKey="id"
options={addressData.states}
labelKey="stateLabel"
optionRenderer={option =>
`${option.stateShortName} (${option.stateName})`}
value={input.value}
selectValue={
Array.isArray(input.value) ? input.value : undefined
}
/>
</FormField>
);
}}
name="state"
id="state"
label="State."
fieldCols={6}
labelCols={3}
controlCols={6}
/>
</Row>
<Row>
<Field
component={props => {
const { input, id, placeholder, type } = props;
const {
fieldCols,
labelCols,
controlCols,
label,
inputClass
} = props;
// The props we want the inner Select.Async textbox to have.
const { name, value, onChange, onBlur, onFocus } = input;
// A suburb was selected so "onChange" is updated along
//with the static form component "Postcode".
const onSuburbChange = value => {
onSuburbStateChange(value);
input.onChange(value);
updatePostcodeValue(value ? value.postcode : null, sectionPrefix);
};
return (
<FormField
id={id}
label={label}
fieldCols={fieldCols}
labelCols={labelCols}
controlCols={controlCols}
inputClass={inputClass}
>
<Select.Async
{...input}
onChange={onSuburbChange}
placeholder="Select suburb"
valueKey="id"
labelKey="suburbName"
value={input.value}
loadOptions={handleSuburbSearch}
backspaceRemoves={true}
/>
</FormField>
);
}}
name="suburb"
id="suburb"
label="Suburb."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
</Row>
<Row>
<Field
component={StaticText}
name="postcode"
id="postcode"
label="Postcode."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
</Row>
</Panel>
);
};
Address.propTypes = {
handleSuburbSearch: PropTypes.func.isRequired,
onSuburbStateChange: PropTypes.func.isRequired
};
const AddressForm = reduxForm({
form: "Address"
})(Address);
let AddressForm2 = connect(
(state, ownProps) => ({
initialValues: state.editClient, // pull initial values from client reducer
enableReinitialize: true
}),
{ reducer } // bind client loading action creator
)(AddressForm);
export default Address;
state.editClient from the Redux tool in Chrome:
Note that address1, suburb and postcode all have values and its these that are not being displayed in the Address component...
I'm not sure what the deal is probably something stupid but when my handle email and handle password handlers are hit, I get null values for text that I entered on the form.
LoginContainer
import React, { Component } from 'react'
import * as AsyncActions from '../actions/User/UserAsyncActions'
import Login from '../components/Login/Login'
class LoginContainer extends Component {
constructor(props) {
super(props)
this.state = {
email: '',
password: ''
}
this.emailIsValid = this.emailIsValid.bind(this)
this.handleEmailInput = this.handleEmailInput.bind(this)
this.handlePasswordInput = this.handlePasswordInput.bind(this)
this.handleLoginPressed = this.handleLoginPressed.bind(this)
}
handlePasswordInput(e, password) {
e.persist()
this.setState(password )
}
handleEmailInput(e, email) {
e.persist()
this.setState(email)
}
handleLoginPressed(e) {
e.persist()
// e.preventDefault()
if (this.emailIsValid(this.state.email) &&
this.passwordIsValid(this.state.password)) {
this.props.login(this.state.email, this.state.password)
}
}
emailIsValid(e, email) {
e.persist()
if (!email) {
return false
}
return true
}
passwordIsValid(e, password) {
e.persist()
if (!password) {
return false
}
return true
}
render(){
return( <Login
handleEmailInput={this.handleEmailInput}
handlePasswordInput={this.handlePasswordInput}
login={this.handleLoginPressed}
/> )
}
}
const mapStateToProps = state => {
return {
requesting: state.user.requesting,
loggedIn: state.user.loggedIn,
token: state.user.token,
session: state.user.session
}
}
export const mapDispatchToProps = {
login: AsyncActions.login
}
export { Login }
export default connect(mapStateToProps, mapDispatchToProps)(LoginContainer)
Login
class Login extends Component {
render(){
return (
<div>
<LoginForm
handleEmailInput={this.props.handleEmailInput}
handlePasswordInput={this.props.handlePasswordInput}
login={this.props.login}
/>
</div>
)
}
}
export default Login
LoginForm
import React, { Component } from 'react'
import { Button, FormControl, FormGroup, ControlLabel, PageHeader } from 'react-bootstrap'
class LoginForm extends Component {
render(){
return (
<div className='ft-login-form'>
<PageHeader className='ft-header'>Login</PageHeader>
<form onSubmit={this.props.login}>
<FormGroup controlId="formBasicText" >
<ControlLabel>Email</ControlLabel>
<FormControl
bsSize="small"
className="ft-username"
componentClass="input"
onChange={this.props.handleEmailInput}
placeholder="Enter mail"
style={{ width: 300}}
type="text"
// value={this.state.email}
/>
<ControlLabel>Password</ControlLabel>
<FormControl
bsSize="small"
className="ft-password"
componentClass="input"
onChange={this.props.handlePasswordInput}
placeholder="Enter Password"
style={{ width: 300}}
type="text"
// value={this.state.password}
/>
</FormGroup>
<Button
className='ft-login-button'
type='submit'>Login</Button>
</form>
</div>)
}
}
export default LoginForm
It looks like you were on the right path with the value={this.state.password}. But since your state is in the parent component, you have to pass the state down and the value becomes value={this.props.value}. The event handlers usually look something like this:
handlePasswordInput(e, password) {
e.persist()
this.setState({ password: e.target.value })
}
They could be different due to the FormControl component but it's worth changing them to see if that's your problem. Also, onChange handlers implicitly pass in e and you have to use a arrow function expression to explicitly pass in anything else.
Edit: If they were able to do something like you mentioned in the comment, they probably did something like this:
handlePasswordInput(e, password) {
e.persist()
const password = e.target.value
this.setState({ password })
}
In es6, { password } is the same as { password: password}