Redux-form how to update Material-UI v4 textField value? - reactjs

How to update TextField value(from state) by using redux-form?
I am using the version below:
"#material-ui/core": "^4.11.0"
"redux-form": "^8.3.6"
Before I use redux-form, I was able to update the TextField value from the onChange event by dispatch to the reducer action such as below:
<TextField
id="name-id"
label="Name"
name="Name"
value={props.Info.Name || ""}
onChange={(e) => {
props.updateTextInput({ //calling reducer
name: e.currentTarget.name,
value: e.currentTarget.value,
});
}}
/>
Now, I want to use the redux form, but I am not able to typing in the input field. I've tried to add value property but not working.
Below are my redux-form code:
const renderTextField = ({
label,
input,
meta: { touched, invalid, error },
...custom
}) => (
<TextField
label={label}
placeholder={label}
value="test value" //try to set value, but not working
error={touched && invalid}
helperText={touched && error}
{...input}
{...custom}
/>
);
<Field
name="Name"
component={renderTextField}
label="Name"
variant="outlined"
fullWidth
value={props.Info.Name || ""} //try to set value, but not working
onChange={(e) => {
props.userUpdateTextInput({
name: e.currentTarget.name,
value: e.currentTarget.value,
});
}}
/>
I found on the {...input} there is an onChange function, it will perform something for redux-form, but at the end, my input text will be removed.

What I missed is the formReducer. After adding the code below, everything working as expected.
import { reducer as formReducer } from 'redux-form';
export default combineReducers({
User: userReducer,
form: formReducer,
});

Related

react-hook-form not triggering onSubmit when using Controller

I have the following form:
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="voucherPrice"
control={control}
defaultValue={false}
rules={{ required: true }}
render={({ field: { onChange, value, ref } }) => (
<Input {...field} onChange={(ev) => handlePriceInputChange(ev)} value={price} type="number" innerRef={ref} />
)}
/>
<p>{errors.voucherPrice?.message}</p>
<Button
variant="contained"
sx={{ mt: 1, mr: 1 }}
type="submit"
>
{"Continue"}
</Button>
</form>
and with this configuration:
function PriceSelection(props) {
const {
register,
handleSubmit,
control,
formState: { errors },
} = useForm({
resolver: yupResolver(schema),
});
const onSubmit = (data) => {
console.log("does not work?", data);
};
const classes = useStylesPriceSelection();
const [selected, setSelected] = useState(false);
const [price, setPrice] = useState("");
const handlePriceInputChange = (ev) => {
console.log("change", price);
setPrice(parseInt(ev.target.value));
};
The function onSubmit does not trigger when I press the submit button. Also I would like the input field to be filled by default by the state price and its value to be sent with the parameter data on the function onSubmit when I push the submit button.
You are mixing useState with react-hook-form and are not updating react-hook-form's internal form state. You don't need to declare a useState for your field.
In your example you are destructering onChange from the field object of <Controller /> but you are never using it for your <Input /> component. Therefore react-hook-form can't update it's form state. As you set your field to be required the onSubmit callback won't get triggered because react-hook-form will never receive an update or value for it.
The correct way would be:
<Controller
name="voucherPrice"
control={control}
rules={{ required: true }}
render={({ field: { ref, onChange, value, ...field } }) => (
<Input {...field} onChange={onChange} value={value} type="number" innerRef={ref} />
)}
/>
Or even shorter:
<Controller
name="voucherPrice"
control={control}
rules={{ required: true }}
render={({ field: { ref, ...field } }) => (
<Input {...field} type="number" innerRef={ref} />
)}
/>
UPDATE
If you need to have access to the value outside of the <Controller />, you should use react-hook-form's watch method. This will allow you to subscribe to the latest value of the voucherPrice field and use it inside your component -> Docs
If you want to set or update the value programmatically you can use the setValue method from react-hook-form -> Docs
const { control, handleSubmit, watch, setValue } = useForm();
const voucherPrice = watch("voucherPrice");
const onButtonClick = () => {
setValue("voucherPrice", <newValue>);
}
If you really need to have a separate useState for your value and want to update it additionally to your react-hook-form field update, you could do the following:
<Controller
name="voucherPrice"
control={control}
rules={{ required: true }}
render={({ field: { ref, onChange, value, ...field } }) => (
<Input
{...field}
onChange={(v) => {
onChange(v);
handlePriceInputChange(v);
}}
value={value}
type="number"
innerRef={ref}
/>
)}
/>
But i would suggest to use the react-hook-form only solution, as it has all the functionality you need to manage your form state.

React Hook Form and React Select Not Working as Expected

Im trying to wrap React Select inside of a React Hook Form with the Controller wrapper component as per the docs (https://react-hook-form.com/get-started#IntegratingControlledInputs)
<Controller
name="ShiftCaptain"
control={control}
render={({ field }) => (
<Select
{...field}
value={selectValue}
options={options}
placeholder={"Select Person"}
onChange={(e) => setSelectValue(e)}
/>
)}
/>
On form submission, the value captured inside the React Select isnt being populated into React Hook Forms:
Any ideas?
TIA
The field object of the render callback which you spread on your <ReactSelect /> component has a value and a onChange property, which RHF needs to link the value and also changes to the value to it's internal form state. Right now you overwriting this, so RHF can't update the value. Try this and it should work:
<Controller
name="ShiftCaptain"
control={control}
defaultValue={null}
render={({ field }) => (
<Select
{...field}
options={options}
placeholder={"Select Person"}
/>
)}
/>
If you want to set a default value for your select after page load you should use the <Controller /> defaultValue prop, which will pass the value to your <ReactSelect />.
Please check the this code sandbox.
https://codesandbox.io/s/react-hook-form-v7-controller-forked-40t3s?file=/src/index.js
const handleOnChange = (e) => {
setSelectedValue(e.value);
};
<label>React Select</label>
<Controller
name="ReactSelect"
control={control}
render={({ field }) => (
<ReactSelect
isClearable
{...field}
value={selectedValue}
onChange={handleOnChange}
options={[
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" }
]}
/>
)}
/>

why is first letter dead in react-hook-form input

i need help to understand why the first letter in the simple input component is not registered.
I've created a simple controlled input from the examples but its not working properly.
i created an example for you https://stackblitz.com/edit/react-9zezqx
const App = () => {
const { register, handleSubmit, watch, errors, reset, control, formState } = useForm({ mode: 'onChange' });
console.log(errors)
return (
<div>
<form onSubmit={handleSubmit(() => console.log("submit"))}>
<Controller
as={TextInput}
name="firstname"
defaultValue=""
control={control}
inputRef={register({ required: true, minLength: 8 })}
hasErrors={errors.firstname !== undefined}
/>
<br/>
<Controller
as={TextInput}
name="hobby"
defaultValue=""
control={control}
inputRef={register({ required: true, minLength: 8 })}
hasErrors={errors.hobby !== undefined}
/>
</form>
</div>
);
}
render(<App />, document.getElementById('root'));
import * as React from 'react';
export const TextInput = (props) => {
return(
<>
<input
type="text"
name={props.name}
value={props.value}
onChange={props.onChange}
ref={props.inputRef}
/>
{props.hasErrors && (<h2>errors!!</h2>)}
</>
)
}
okay i found the bug causing it in 'onBlur' aswell
reValidateMode: 'onBlur'
Swap the mode to onBlur, this will improve the performance, will trigger only when the user leaves the field, which is suppose to happen, and also does not swallow the first input.
onChange skips the first letter, because the default value will be used for the initial onChange call, which is empty.
You are probably using an uncontrolled input. If that's the case use defaultValue instead of value.
Reference
This is the problem here, you are try to use Controller with register:
https://react-hook-form.com/api#Controller
<Controller
as={TextInput}
name="hobby"
defaultValue=""
control={control}
/>
or
https://react-hook-form.com/api#register
<TextInput inputRef={register} />

Checkbox onChange event is not handled by handleChange props by Formik

I was building simple Form using React and Formik library.
I have added check box inside the form tag which is wrapped by withFormik wrapper of formik library.
I have tried to changing from
<input
type="checkbox"
name="flag"
checked={values.flag}
onChange={handleChange}
onBlur={handleBlur}
/>
to
<input
type="checkbox"
name="flag"
value={values.flag}
onChange={handleChange}
onBlur={handleBlur}
/>
but none is working.
the component is as following
import { withFormik } from 'formik';
...
const Form = props => (
<form>
<input
type="checkbox"
name="flag"
checked={props.values.flag}
onChange={props.handleChange}
onBlur={props.handleBlur}
/>
<input
type="text"
name="name"
checked={props.values.name}
onChange={props.handleChange}
onBlur={props.handleBlur}
/>
</form>
);
const WrappedForm = withFormik({
displayName: 'BasicForm',
})(Form);
export default WrappedForm;
It should change props.values when clicking checkbox.
but it doesn't change props data at all.
Btw, it changes props data when typing in text input box.
This only happens with checkbox.
Using the setFieldValue from Formik props, you can set the value of the check to true or false.
<CheckBox
checked={values.check}
onPress={() => setFieldValue('check', !values.check)}
/>
My answer relates to react-native checkbox.
This article is very helpful. https://heartbeat.fritz.ai/handling-different-field-types-in-react-native-forms-with-formik-and-yup-fa9ea89d867e
Im using react material ui library, here is how i manage my checkboxes :
import { FormControlLabel, Checkbox} from "#material-ui/core";
import { Formik, Form, Field } from "formik";
<Formik
initialValues={{
check: false
}}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({ values, setFieldValue }) => (
<Form className="gt-form">
<FormControlLabel
checked={values.check}
onChange={() => setFieldValue("check", !values.check)}
control={<Checkbox />}
label="save this for later"
/>
</Form>
)}
</Formik>

React Datepicker with redux-form

How to make the react-datepicker bind with redux-form?
I have this redux-form field:
<Field name="due_date" component={props =>
<DatePicker
{...props}
readOnly={true}
selected={this.state.due_date}
value={this.state.due_date}
onChange={this.handleDueDate}
/>
} />
Whenever i submit the redux form does return an empty object not binding the datepicker's value...
my onChange :
handleDueDate(date) {
this.setState({
due_date: moment(date).format('L')
}, () => {
// do I need to dispatch and action here to update the redux-form in state tree?
})
}
you have to make a custom component to validate and use datepicker with redux-form
Try this
const datePicker = ({ input, label, type, className, selected, meta: { touched, error } }) => (
<div>
<div>
<DatePicker {...input}
selected={selected} placeholder={label}
type={type} className={className}
peekNextMonth
showMonthDropdown
showYearDropdown
dropdownMode="select"
/>
{touched && error && <span className="error_field">{error}</span>}
</div>
</div>
)
and then pass props to that custom component
<Field
name="date_of_birth"
component={datePicker}
type="text"
selected={this.state.date_of_birth}
onChange={this.handleChange.bind(this)}
className="form-control"
/>
For future readers, just go to this link: DatePicker in Redux Form
first, I created the component like metioned in link above and just passed the selected prop in it. in my case:
<Field
name="due_date"
component={DatePickerComponent}
selected={this.state.date_of_briefing} />

Resources