I am trying to build a simple form with React-Final-Form like this:
import * as React from "react";
import {
PrimaryButton,
} from "office-ui-fabric-react/lib/Button";
import { Form , Field } from "react-final-form";
import { FORM_ERROR } from "final-form";
import { IUserFormValues } from "../../models/user";
import { RootStoreContext } from "../../stores/rootStore";
import TextInputNew from "./TextInputNew";
const NewUIForm = () => {
const rootStore = React.useContext(RootStoreContext);
const { login } = rootStore.userStore;
return (
<Form
onSubmit={(values: IUserFormValues) =>
login(values).catch((error) => ({
[FORM_ERROR]: error,
}))
}
render={({
handleSubmit,
}) => (
<Form onSubmit={handleSubmit}>
<Field name="email" component={TextInputNew} />
<Field name="email" component={TextInputNew} />
<PrimaryButton type='submit' text="Save" />
</Form>
)}
/>
);
};
export default NewUIForm;
The TextInputNew Component is this:
import * as React from "react";
import { TextField } from "office-ui-fabric-react/lib/TextField";
import { FieldRenderProps } from "react-final-form";
interface IProps extends FieldRenderProps<string, HTMLInputElement> {}
const TextInputNew: React.FC<IProps> = ({ input }) => {
return (
<div>
<input {...input} />
<TextField label="Standard" />
</div>
);
};
export default TextInputNew;
Then I got this error when I use this NewUIForm component
Error: Must specify either a render prop, a render function as children, or a component prop to ReactFinalForm
By the way, the UI framework is Fluent-UI
Can anyone help me? Thanks!!
You're second <Form> should be <form>.
<form onSubmit={handleSubmit}>
<Field name="email" component={TextInputNew} />
<Field name="email" component={TextInputNew} />
<PrimaryButton type='submit' text="Save" />
</form>
To anyone else who might encounter this vague error message, the issue is something going wrong in the render function of <Form>.
For OP, it was using the wrong form tag inside of <Form>.
For me, it was a misspelled property on a <Field> component (components={MyComponent}, oops).
Since the error can be caused by any number of reasons and the message wasn't very specific, one can get an idea of where the problem might be via browser debugger, in my case this is what it looked like:
Related
I'm learning react and I'm having some difficulties. At the moment my question is related to a Login page using ReactJS, Typescript and styled-components. Where I only have the email and password part. I'm manipulating the form with the react hook form, but I have a problem. When I run a console.log of the values of my email and password keys, it just returns undefined. And no error is pointed out in the console.
enter image description here
Here is my code.
import React from "react";
import { useForm, SubmitHandler } from "react-hook-form";
import { Form, TitleSecondary } from "./Form.style";
import { Button } from "../Button/Button";
import { InputContainer, InputLabel, InputField } from "./Form.style";
interface IForm {
email: string;
password: string;
}
export const FormLogin = React.forwardRef<HTMLInputElement>(( props, ref) => {
const { register, handleSubmit } = useForm<IForm>();
const onSubmit: SubmitHandler<IForm> = (data) => console.log(data);
return (
<Form onSubmit={handleSubmit(onSubmit)}>
<TitleSecondary>Login</TitleSecondary>
<InputContainer>
<InputLabel htmlFor="email">Email</InputLabel>
<InputField
{...register("email")}
id="email"
type="email"
placeholder=""
ref={ref}
required
/>
</InputContainer>
<InputContainer>
<InputLabel htmlFor="password">Password</InputLabel>
<InputField
{...register("password")}
id="password"
type="password"
placeholder="mail#example.com"
ref={ref}
required
/>
</InputContainer>
<Button />
</Form>
)
})
I confess that I have tried several things since then, but none have been successful.
I took the example from the documentation :
import React from "react";
import { useForm } from "react-hook-form";
export default function App() {
const { register, handleSubmit, watch, formState: { errors } } = useForm();
const onSubmit = data => console.log(data);
console.log(watch("example"));
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input defaultValue="test" {...register("example")} />
<input type="submit" />
</form>
);
}
But on every change or on submit, I got undefined for each field
I tried to install the library again but nothing change and I got undefined everywhere...seems to be a problem with the register function. Does anybody got the same issue ?
With v7 the usage of register changed as noted in the comments. If you still need to use v6, you have to write it like this:
function App() {
const { register, handleSubmit, watch, formState: { errors } } = useForm();
const onSubmit = data => console.log(data);
console.log(watch("example"));
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input defaultValue="test" name="example" ref={register} />
<input type="submit" />
</form>
);
}
Docs v6
In my case it was a typo:
<input defaultValue="test" {...(register('name'), { required: true })} />
// submit => { name: undefined }
Instead of:
<input defaultValue="test" {...(register('name', { required: true }))} />
// submit => { name: "test" }
Hopefully it can help someone else.
In my case, I was using a Controller, so to fix the Undefined value I just had to pass defaultValues to useForm.
See the rules section here: https://react-hook-form.com/api/useform/watch
const { register, handleSubmit, control, setValue} = useForm<MyFormValues>({
defaultValues : {
receiveUpdates: false
}
});
<Controller
control={control}
name="receiveUpdates"
render={({ field }) => (
<FormControlLabel
control={
<Checkbox
ref={field.ref}
checked={field.value}
onChange={field.onChange}
/>
}
label="Receive Email Updates?"
labelPlacement="start"
/>
)}
/>
I had this issue when using the Input component from reactstrap. Using that component made all my values undefined. I switch the Input to a normal input and was able to read in values
Before:
<Input
placeholder="Password"
type="password"
id="password"
defaultValue=""
{...register('password')}
required
/>
Fixed:
<input
placeholder="Password"
type="password"
id="password"
defaultValue=""
{...register('password')}
required
/>
In my case I installed like "npm i react-hook-form" and I don't know why, but it was installed ^6.15.8 version, and I removed it and try again and then it was install correctly. So try to check out your version of react-hook-form
I am trying to use react-hook-form with my customized date-picker, but I only see this example (Is it possible to use react-datepicker with react hooks forms?), which is using the default react-date-picker.
However, it just only works on the original react-date-picker.
I tried the same way with my customized date-picker, and it doesn't work...
This is my customized date-picker:
import React, { useState } from 'react';
import ReactDatePicker from 'react-datepicker';
import tw from "date-fns/locale/zh-TW";
import "react-datepicker/dist/react-datepicker.css";
const DatePicker = props => {
const [date, setDate] = useState('');
return (
<ReactDatePicker
className="form-control"
selected={date}
onChange={date => setDate(date)}
locale={tw}
dateFormat="yyyy/MM/dd"
dateFormatCalendar="yyyy年 MM月"
isClearable
/>
)
};
export default DatePicker;
Here is how I use react-hook-form with my customized date-picker:
import React from 'react';
import { useForm, Controller } from 'react-hook-form';
import DatePicker from '../../components/UI/Form/DatePicker';
const Form = props => {
const { register, handleSubmit, control} = useForm();
const onSubmit = (data) => {
console.log(data);
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>First Name:</label>
<input type="text" name='firstName' ref={register} />
<label>Last Name:</label>
<input type='text' name='lastName' ref={register} />
<label>birthday:</label>
<Controller as={DatePicker} control={control} valueName="selected" name="birthday" />
<input type="submit" value="Submit" />
</form>
);
}
export default Form;
After I submit the form, the 'birthday' value is undefined.
Do I still need to add any props to my customized date-picker?
{
birthday: undefined,
firstName: "Mike",
lastName: "Smith"
}
The customised form control currently does not offer any props to control it from outside the component. For someone actually using the component, it has to have both selected and onChange fields to extract value out of it (The react-date-picker has these props and hence works)
Controller by default has an onChange which reads from an event passed to it, which is why you see it omitted from examples like this:
<Controller as={TextField} name="TextField" control={control} defaultValue="" />
To change your custom component to work with Controlller syntax, you can expose the selected and onChange accordingly:
const DatePicker = ({ selected, onChange }) => {
return (
<ReactDatePicker
className="form-control"
selected={selected}
onChange={onChange}
locale={tw}
dateFormat="yyyy/MM/dd"
dateFormatCalendar="yyyy年 MM月"
isClearable
/>
)
};
and on the Controller:
<Controller
as={DatePicker}
control={control}
valueName="selected"
name="birthday"
onChange={(date) => date};
/>
Also it's better if you pass onChangeName="onChangeDates" instead so you can pass value in.
<ControllerWrapper
as={
<DatePicker
error={has(formErrors, fieldsConfiguration.datePicker.name)}
/>
}
rules={fieldsConfiguration.datePicker.rules}
name={fieldsConfiguration.datePicker.name}
onChangeName="onChangeDates"
onChange={dateRangePickerSelector}
/>
I am currently writing my first React Project for a class assignment. I am trying to make a login page that navigates to a new dashboard page. I do not want any fancy security, so I wanted it just to have "if password === this password then go to dashboard, if not then error message.
I have the button working fine without validation, and I have my handlers for the text input working as I can display what is typed by using this.state.username and this.state.password in my login-form.js file.
The problem I can't figure out is how to reference/use those states in my login-button.js file so I can create that if statement validator? Can anyone help?
Here is my login-form.js file:
import React from 'react';
import "./login-form.css";
import logo from './../../logo-beesecure-2-tm.png';
import Login_btn from './../login-button/login-button';
class Login_Form extends React.Component {
constructor(props){
super(props);
this.state = { username: '', password: '' };
}
handleChange = ({ target }) => {
this.setState({ [target.name]: target.value });
};
render() {
return (
<div className='login-container'>
<img src={logo} className="App-logo" alt="logo" />
<p>LOGIN</p>
<form onSubmit="" className="login-form">
<input
type="text"
placeholder="Username"
name="username"
value={this.state.username}
onChange={this.handleChange}
/>
<input
type="password"
placeholder="Password"
name="password"
value={this.state.password}
onChange={this.handleChange}
/>
</form>
<Login_btn />
<h2>Your username is: {this.state.username}</h2>
<h2>Your password is: {this.state.password}</h2>
</div>
);
}
}
export default Login_Form;
And here is my login-button.js file:
import './login-button.css';
import React from 'react';
import { useHistory } from "react-router-dom";
import Login_Form from '../login-form/login-form';
function Login_btn() {
let history = useHistory();
function handleClick() {
history.push("/dashboard");
}
return (
<button className="Login-Button" onClick={handleClick}>Login</button>
);
}
export default Login_btn;
Thank you in advance!
You can pass in the states from your <Login_Form /> into your <Login_btn /> by using props like so:
<Login_btn username={this.state.username} password={this.state.password} />
Then you can reference the props in your <Login_btn />:
function Login_btn(props) {
let history = useHistory();
function handleClick() {
const { username, password } = props;
history.push("/dashboard");
}
return (
<button className="Login-Button" onClick={handleClick}>Login</button>
);
}
You can read more about props here: https://reactjs.org/docs/components-and-props.html
I am using redux-form-material-ui for my form. With below code, i cannot type anything on the textfield. I mean to say nothing gets type in the textfield. There are two textfield in my form and one Autocomplete. One is for device name and another for timeout value. Autocomplete works though. Why is it not showing the text i have typed?
What might be the reason for this issue? Have i done somewhere mistake?
Please see an image attached. I cant write anything in device name and timeout input box. Only autocomplete box can be selected and is shown on input box.
Here is my code
import React, { Component } from 'react';
import _ from 'lodash';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import {
AutoComplete as MUIAutoComplete, MenuItem,
FlatButton, RaisedButton,
} from 'material-ui';
import {
AutoComplete,
TextField
} from 'redux-form-material-ui';
const validate = values => {
const errors = {};
const requiredFields = ['deviceName', 'deviceIcon', 'deviceTimeout'];
requiredFields.forEach(field => {
if (!values[field]) {
errors[field] = 'Required';
}
});
return errors;
};
class DeviceName extends Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.handleNext();
}
render() {
const {
handleSubmit,
fetchIcon,
stepIndex,
handlePrev,
pristine,
submitting
} = this.props;
return (
<div className="device-name-form">
<form>
<div>
<Field
name="deviceName"
component={TextField} {/* cannot type */}
floatingLabelStyle={{ color: '#1ab394' }}
hintText="Device Name"
onChange={(e) => this.setState({ deviceName: e.target.name })}
/>
</div>
<div>
<Field
name="deviceIcon"
component={AutoComplete} {/* works */}
hintText="icon"
openOnFocus
filter={MUIAutoComplete.fuzzyFilter}
className="autocomplete"
dataSource={listOfIcon}
onNewRequest={(e) => { this.setState({ deviceIcon: e.id }); }}
/>
</div>
<div>
<Field
name="deviceTimeout"
component={TextField} {/* cannot type */}
floatingLabelStyle={{ color: '#1ab394' }}
hintText="Device Timeout"
ref="deviceTimeout" withRef
onChange={(e) => this.setState({ deviceTimeout: e.target.name })}
/>
</div>
<div style={{ marginTop: 12 }}>
<RaisedButton
label={stepIndex === 4 ? 'Finish' : 'Next'}
primary
disabled={pristine || submitting}
className="our-btn"
onTouchTap={(e) => handleSubmit(e)}
/>
</div>
</form>
</div>
);
}
}
const mapStateToProps = ({ fetchIcon }) => ({
fetchIcon
});
const DeviceForm = reduxForm({
form: 'DeviceForm',
validate,
})(DeviceName);
export default connect(mapStateToProps)(DeviceForm);
By adding onChange to your Fields, aren't you preventing redux form from accepting the new values from that input field? Is there a reason you are attempting to add these to your Component state?
The examples in the documentation certainly suggest you should not need to do this - http://redux-form.com/6.1.1/examples/material-ui/
I guess you can simplify your form as-
class DeviceName extends Component {
handleSubmit = (values) => {
console.log(values); // Do something with values
}
render() {
const {
....
handleSubmit //***Change
} = this.props;
return (
<div className="device-name-form">
<form onSubmit={handleSubmit(this.handleSubmit)}>
<div>
<Field
name="deviceName"
component={TextField} {/* cannot type */}
floatingLabelStyle={{ color: '#1ab394' }}
hintText="Device Name"
//*** line removed
/>
</div>
.....
.....
<div style={{ marginTop: 12 }}>
<RaisedButton
type="submit" // setting type
label={stepIndex === 4 ? 'Finish' : 'Next'}
primary
disabled={pristine || submitting}
className="our-btn"
/>
</div>
</form>
</div>
);
}
}
I would guess that the problem is in your onChange handlers - you probably need to use target.value rather than target.name:
onChange={(e) => this.setState({ deviceTimeout: e.target.value})
I had the same issue, turned out I used the wrong import. I was using the normal import:
import { Field, reduxForm } from 'redux-form'
Because my store is immutable (using Immutable.js) I had to use the immutable import:
import { Field, reduxForm } from 'redux-form/immutable'
Some kind of error logging for redux-form would have been handy in this case.